package com.alibaba.citrus.cr.mn.order.center.facade.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.citrus.cr.b2b.trade.order.facade.common.SetOrderTag;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderLineWriteRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderQueryServiceRepository;
import com.alibaba.citrus.cr.b2b.trade.order.repository.OrderWriteRepository;
import com.alibaba.citrus.cr.common.constant.OrderFeaturesKey;
import com.alibaba.citrus.cr.common.enums.ordercenter.*;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.lock.SaleRedisLock;
import com.alibaba.citrus.cr.common.util.DateUtils;
import com.alibaba.citrus.cr.common.util.OpenApiUtils;
import com.alibaba.citrus.cr.common.util.TimeUtil;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.FulfillmentOrderAbilityAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.ItemQueryAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.ItemSpecQueryAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.WmsOrderAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.FulfillmentOrderSearchOrderRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.ItemSearchAbilityRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.ItemUnitAbilityRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.*;
import com.alibaba.citrus.cr.mn.order.center.facade.function.asynctask.AsyncTaskCreateService;
import com.alibaba.citrus.cr.mn.order.center.facade.function.asynctask.OrderAsyncTaskListenerConsumerSelector;
import com.alibaba.citrus.cr.mn.order.center.facade.function.common.SendMsgService;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.ForecastOrderQueryRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.service.dataobject.response.*;
import com.alibaba.cloud.retail.delivery.api.model.delivery.enums.OrderTypeEnum;
import com.alibaba.cloud.retail.delivery.api.model.delivery.request.fulfillment.*;
import com.alibaba.cloud.retail.delivery.api.model.delivery.response.fulfillment.BatchCloseFulfillmentOrderOpenApiResponse;
import com.alibaba.cloud.retail.delivery.api.model.delivery.response.fulfillment.BcFulfillmentOrderDetailSearchResponse;
import com.alibaba.cloud.retail.wms.api.constants.WmsOrderMainTypeEnum;
import com.alibaba.cloud.retail.wms.api.model.orders.common.WarehousingOrderDTO;
import com.alibaba.cloud.retail.wms.api.model.orders.common.WarehousingSubOrderDTO;
import com.alibaba.cloud.retail.wms.api.model.orders.common.WmsOrderDetailDTO;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.contants.BcOrderConstants;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOrderBizIdsRequest;
import com.epoch.app.crb2btradecenter.domain.order.dto.UpdateOrderResponse;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.QuerySalesOrderLineByIdsRequest;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.UpdateCumulativeNoticeQuantityAndFeaturesRequest;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.UpdateCumulativeNoticeQuantityAndFeaturesResponse;
import com.epoch.app.crb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.crb2btradecenter.domain.orderline.service.OrderLineService;
import com.epoch.app.crb2btradecenter.dto.request.OrderQueryRequest;
import com.epoch.app.crb2btradecenter.messagetask.dto.LoadRequest;
import com.epoch.app.crb2btradecenter.messagetask.model.MessageTask;
import com.epoch.app.crb2btradecenter.messagetask.service.MessageTaskService;
import com.epoch.app.crb2btradecenter.model.enums.MessageTaskTypeEnum;
import com.epoch.app.crb2btradecenter.sdo.OrderLineSDO;
import com.epoch.app.crb2btradecenter.sdo.OrderSDO;
import com.epoch.app.crforecastsales.domian.forecastorder.model.ForecastOrder;
import com.epoch.app.crforecastsales.domian.forecastorder.service.ForecastOrderService;
import com.epoch.app.crforecastsales.domian.forecastorderline.model.ForecastOrderLine;
import com.epoch.app.crforecastsales.domian.forecastorderline.service.ForecastOrderLineService;
import com.epoch.app.crforecastsales.enums.ForecastStatusEnum;
import com.epoch.app.crforecastsales.sdo.ForecastOrderLineSDO;
import com.epoch.app.crforecastsales.sdo.ForecastOrderSDO;
import com.epoch.app.mnordercenter.model.dto.CommonAsyncMessageResponse;
import com.epoch.app.mnordercenter.model.dto.OrderAsyncTaskRequest;
import com.epoch.app.mnordercenter.orderasynctasklistener.dto.*;
import com.epoch.app.mnordercenter.orderasynctasklistener.service.OrderAsyncTaskListenerService;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.alibaba.citrus.cr.mn.order.center.common.constants.RedisLockConstants.*;

/**
 * @author zhangxiaorui
 * @ClassName OrderAsyncTaskListenerServiceImpl
 * @description: TODO
 * @date 2023/05/18 15:39
 * @version: 1.0
 */
@Service
public class OrderAsyncTaskListenerServiceImpl implements OrderAsyncTaskListenerService {
    private static final Log log = Log.getLogger(OrderAsyncTaskListenerServiceImpl.class);

    //履约单消息code
    private static final String FULFILLMENT_ORDER_CREATE = "fulfillment_order_create";
    private static final String FULFILLMENT_ORDER_UPDATE = "fulfillment_order_update";
    private static final String FULFILLMENT_ORDER_SUBMIT = "fulfillment_order_submit";
    private static final String FULFILLMENT_ORDER_CLOSE = "fulfillment_order_close";
    private static final String FULFILLMENT_ORDER_CANCEL = "fulfillment_order_cancel";
    //履约单方向类型
    private static final int FULFILLMENT_ORDER_FORWARD = 1; // 正向履约单
    private static final int FULFILLMENT_ORDER_REVERSE = 2; // 逆向履约单
    //正向履约单
    private static final String CREATE_ORDER_URL = "/fulfillment-center/delivery/dubbo/api/fulfillment/createOrder";
    //逆向履约单
    private static final String CREATE_REVERSE_ORDER_URL = "/fulfillment-center/delivery/dubbo/api/fulfillment/createReverseOrder";
    //查询履约单
    private static final String SEARCH_ORDER_URL = "/fulfillment-center/delivery/dubbo/api/fulfillment/searchList";
    //关闭履约单
    private static final String CLOSE_ORDER_URL = "/fulfillment-center/delivery/dubbo/api/fulfillment/finish";
    //取消履约单
    private static final String CANCEL_ORDER_URL = "/fulfillment-center/delivery/dubbo/api/fulfillment/cancel";
    //SAP回调后调用其他中心时默认用户名
    private static final String DEFAULT_USER = "system";

    private static final EnumSet<MessageTaskTypeEnum> canHandlerMessageTaskTypeSet = EnumSet.of(
            MessageTaskTypeEnum.OC_SALES_ORDER_BATCH_CREATE,
            MessageTaskTypeEnum.OC_DIRECT_SALES_ORDER_BATCH_CREATE,
            MessageTaskTypeEnum.OC_RETURN_ORDER_BATCH_CREATE,
            MessageTaskTypeEnum.OC_EXCHANGE_ORDER_BATCH_CREATE,
            MessageTaskTypeEnum.OC_FORECAST_ORDER_BATCH_CREATE
    );

    @Resource
    private AsyncTaskCreateService asyncTaskCreateService;
    @Resource
    private MessageTaskService messageTaskService;
    @Resource
    private OrderQueryServiceRepository orderQueryServiceRepository;
    @Resource
    private OrderLineWriteRepository orderLineWriteRepository;
    @Resource
    private OrderWriteRepository orderWriteRepository;
    @Resource
    private FulfillmentOrderAbilityAdapter fulfillmentOrderAbilityAdapter;
    @Resource
    private List<OrderAsyncTaskListenerConsumerSelector> orderAsyncTaskListenerConsumerSelectors;
    @Resource
    private WmsOrderAdapter wmsOrderAdapter;
    @Resource
    private EpochMessageService messageService;
    @Resource
    private OpenApiUtils openApiUtils;
    @Resource
    private SendMsgService sendMsgService;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderLineService orderLineService;
    @Resource
    private ItemQueryAdapter itemQueryAdapter;
    @Resource
    private ItemSpecQueryAdapter itemSpecQueryAdapter;
    @Resource
    private EpochCacheService epochCacheService;
    @Resource
    private ForecastOrderQueryRepository forecastOrderQueryRepository;
    @Resource
    private ForecastOrderLineService forecastOrderLineService;
    @Resource
    private ForecastOrderService forecastOrderService;
    /**
     * 订单创建消息处理
     */
    @Override
    public Result<Void> consumer(OrderAsyncTaskRequest orderAsyncTaskRequest) {
        log.info("OrderAsyncTask_consumer request={}", JSONObject.toJSONString(orderAsyncTaskRequest));

        MessageTask messageTask = queryMessageTask(orderAsyncTaskRequest);

        if (Objects.isNull(messageTask) || canHandlerMessageTaskTypeSet.stream().noneMatch(p -> p.getValue().equals(messageTask.getType()))) {
            log.info("OrderAsyncTask_consumer_skip");
            return Result.success(null, "", "");
        }

        // 商业服务调用
        return doCreate(messageTask);
    }

    private MessageTask queryMessageTask(OrderAsyncTaskRequest orderAsyncTaskRequest) {
        try {
            if (StringUtils.isBlank(orderAsyncTaskRequest.getSequenceNo())) {
                return null;
            }
            LoadRequest loadRequest = new LoadRequest();
            loadRequest.setBatchNo(orderAsyncTaskRequest.getSequenceNo());
            MessageTask messageTask = messageTaskService.load(loadRequest);

            log.info("OrderAsyncTask_queryMessageTask request={}, result={}",
                    JSONObject.toJSONString(loadRequest), JSONObject.toJSONString(messageTask));

            if (Objects.isNull(messageTask)) {
                return null;
            }
            return messageTask;
        } catch (Exception e) {
            log.warn("未获取到任务信息返回空，{}", JSONObject.toJSONString(orderAsyncTaskRequest));
            return null;
        }
    }

    private Result<Void> doCreate(MessageTask messageTask) {
        try {
            if (StringUtils.isBlank(messageTask.getResultContent())) {
                return Result.success(null, "", "");
            }

            // 下载OSS文件
            String ossContent = asyncTaskCreateService.downloadOfTaskParams(messageTask.getResultContent());
            if (StringUtils.isBlank(ossContent)) {
                return Result.success(null, "", "");
            }

            createOrderBySelectedBizCreateService(ossContent, messageTask);

        } catch (Exception ex) {
            log.error("创建订单失败", ex);
        }
        return Result.success(null, "", "");
    }

    private void createOrderBySelectedBizCreateService(String requestParamsFromOss, MessageTask messageTask) {
        log.info("createOrderBySelectedBizCreateService requestParamsFromOss={}", requestParamsFromOss);

        MessageTaskTypeEnum messageTaskTypeEnum = Arrays.stream(MessageTaskTypeEnum.values())
                .filter(source -> Objects.equals(messageTask.getType(), source.getValue()))
                .findFirst().orElse(null);

        if (Objects.isNull(messageTaskTypeEnum)) {
            return;
        }

        Optional<OrderAsyncTaskListenerConsumerSelector> strategyServiceOptional = orderAsyncTaskListenerConsumerSelectors
                .stream()
                .filter(t -> t.getMessageTaskType().equals(messageTaskTypeEnum))
                .findAny();

        OrderAsyncTaskListenerConsumerSelector orderAsyncTaskListenerConsumer = strategyServiceOptional.orElse(null);
        if (Objects.isNull(orderAsyncTaskListenerConsumer)) {
            return;
        }
        orderAsyncTaskListenerConsumer.doConsumer(requestParamsFromOss, messageTask);
    }

    /**
     * 出入库单消息处理
     */
    @Override
    public Result<Void> wmsMessageConsumer(WmsMessageConsumerRequest wmsMessageConsumerRequest) {
        log.info("OrderAsyncTaskListenerServiceImpl#wmsMessageConsumer wmsMessageConsumerRequest:{}", JSON.toJSONString(wmsMessageConsumerRequest));
        if (StringUtils.isBlank(wmsMessageConsumerRequest.getMessage())) {
            return Result.success(null);
        }

        JSONObject originMessage = JSONObject.parseObject(wmsMessageConsumerRequest.getMessage());
        String tag = originMessage.getString("tag");
        if (StringUtils.isBlank(tag)) {
            return Result.success(null);
        }

        WarehousingOrderDTO warehousingOrderDTO = JSONObject.parseObject(originMessage.getString("wmsOrderDTO"), WarehousingOrderDTO.class);
        Result<Void> result;
        switch (tag) {
            case "OUT_BOUND_ORDER_CREATE": // 出入库单创建消息
                result = inOutInventoryCreateConsumer(warehousingOrderDTO);
                break;
            case "OUT_BOUND_ORDER_CONFIRM": // 出入库单确认消息
                result = inOutInventoryConfirmConsumer(warehousingOrderDTO);
                break;
            case "ORDER_DETAIL_UPDATE": // 出入库单修改/删除消息
                result = inOutInventoryCreateConsumer(warehousingOrderDTO);
                break;
            default:
                log.info("wmsMessageConsumer tag:{}", tag);
                result = Result.success(null);
                break;
        }
        return result;
    }

    /**
     * 处理出入库单创建消息
     */
    private Result<Void> inOutInventoryCreateConsumer(WarehousingOrderDTO warehousingOrderDTO) {
        Integer mainOrderType = warehousingOrderDTO.getMainOrderType();
        if (!mainOrderType.equals(WmsOrderMainTypeEnum.SALES_OUT.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.RETURN_IN.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.OUT.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.OTHER_OUT.getValue())) {
            return Result.success(null);
        }

        String saleOrderNo = warehousingOrderDTO.getBizOrderId();
        QueryByOrderBizIdsRequest request = new QueryByOrderBizIdsRequest();
        request.setOrderBizIds(Lists.newArrayList(saleOrderNo));
        List<OrderSDO> orderSDOS = orderQueryServiceRepository.queryByOrderBizIds(request, true);
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryCreateConsumer orderSDOS:{}", JSON.toJSONString(orderSDOS));
        if (CollectionUtils.isEmpty(orderSDOS)) {
            return Result.success(null);
        }

        OrderSDO orderSDO = orderSDOS.get(0);
        if (OrderCategoryEnum.COMPANY.getCode().equals(orderSDO.getOrderCategoryCode()) && SetOrderTag.RETURN.equals(orderSDO.getOrderTag())) {
            // B-b退货订单无需更新累计待出库数，直接返回即可
            return Result.success(null);
        }

        // 查询出入库单数据
        List<WarehousingOrderDTO> warehousingOrderDTOS = wmsOrderAdapter.queryWmsOrderByOtherOrderContainDeleted(saleOrderNo);
        if (CollectionUtils.isEmpty(warehousingOrderDTOS)) {
            return Result.success(null);
        }
        //如果因为删除了，下面更新累计待出库数量=0
        warehousingOrderDTOS = warehousingOrderDTOS.stream().filter(it -> !Objects.equals(-1, it.getOrderStatus())).collect(Collectors.toList());
        log.info("OrderAsyncTaskListenerServiceImpl inOutInventoryCreateConsumer warehousingOrderDTOS={}",JSON.toJSONString(warehousingOrderDTOS));
        List<WmsOrderDetailDTO> allOutWmsDetailList = new ArrayList<>();
        for (WarehousingOrderDTO warehousingOrder : warehousingOrderDTOS) {
            List<WmsOrderDetailDTO> wmsOrderDetailList = warehousingOrder.getWmsOrderDetailList();
            if (CollectionUtils.isNotEmpty(wmsOrderDetailList)) {
                allOutWmsDetailList.addAll(wmsOrderDetailList);
            }
        }

        Map<String, Long> bizSubNoOutQuantityMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(allOutWmsDetailList)) {
            List<WmsOrderDetailDTO> detailDTOList = new ArrayList<>(
                    allOutWmsDetailList.stream()
                            .collect(Collectors.toMap(
                                    WmsOrderDetailDTO::getWmsOrderDetailId,       // keyMapper
                                    Function.identity(), // valueMapper
                                    (existing, replacement) -> replacement // mergeFunction, in case of collision keep the existing
                            )).values());
            bizSubNoOutQuantityMap = detailDTOList.stream().collect(Collectors.groupingBy(WmsOrderDetailDTO::getBizSubOrderId, Collectors.summingLong(WmsOrderDetailDTO::getGoodsQuantity)));
        }

        try {
            Map<String, OrderLineSDO> orderLineSDOMap = Nullable.stream(orderSDO.getOrderLineSDOS())
                    .collect(Collectors.toMap(OrderLineSDO::getSerialNumber, Function.identity(), (v1, v2) -> v1));
            for (Map.Entry<String, OrderLineSDO> lineSDOEntry : orderLineSDOMap.entrySet()) {
                OrderLineSDO orderLineSDO = lineSDOEntry.getValue();
                if (CollectionUtil.isEmpty(bizSubNoOutQuantityMap)) {
                    // 兼容出入库单删除消息，删除后清零累计待出库数量/累计交货数量
                    orderLineSDO.setCumulativeWaitOutboundQuantity("0");
                    orderLineSDO.setCumulativeDeliveryQuantity("0");
                    orderLineWriteRepository.modifyOrderLine(orderLineSDO);
                } else if (bizSubNoOutQuantityMap.containsKey(lineSDOEntry.getKey())) {
                    BigDecimal outBoundQuantity = BigDecimal.valueOf(bizSubNoOutQuantityMap.get(lineSDOEntry.getKey()))
                            .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                    // 库存单位转换成销售单位
                    String cumulativeWaitOutboundQuantity = convertUnitQuantity(outBoundQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                    orderLineSDO.setCumulativeWaitOutboundQuantity(cumulativeWaitOutboundQuantity);
                    orderLineWriteRepository.modifyOrderLine(orderLineSDO);
                }
            }
            handleGroupQuantity(orderSDO);
        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#inOutInventoryCreateConsumer modifyOrderLine error", e);
        }

        return Result.success(null);
    }

    private OrderSDO getGroupOrder(OrderSDO orderSDO) {
        //查询关联的F-B订单修改状态
        QueryByOrderBizIdsRequest groupRequest = new QueryByOrderBizIdsRequest();
        groupRequest.setOrderBizIds(Lists.newArrayList(orderSDO.getRelationNo()));
        List<OrderSDO> groupOrderSDOS = orderQueryServiceRepository.queryByOrderBizIds(groupRequest, Boolean.TRUE);
        if (CollectionUtils.isEmpty(groupOrderSDOS)) {
            return null;
        }
        log.info("OrderAsyncTaskListenerServiceImpl#getGroupOrder#groupRequest={},groupOrderSDOS={}", JSON.toJSONString(groupRequest), JSON.toJSONString(groupOrderSDOS));
        //F-B订单
        return groupOrderSDOS.get(0);
    }

    private void handleGroupQuantity(OrderSDO orderSDO) {
        try {
            if (!(OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode()) && !"ZOR".equals(orderSDO.getOrderType()))) {
                return;
            }
            //F-B订单
            OrderSDO groupOrderSDO = getGroupOrder(orderSDO);
            if(Objects.isNull(groupOrderSDO)){
                return;
            }
            //B-b订单明细
            Map<String, OrderLineSDO> orderLineSDOMap = orderSDO.getOrderLineSDOS().stream().collect(Collectors.toMap(OrderLineSDO::getSerialNumber, Function.identity(), (p1, p2) -> p2));
            //F-B订单子单同步状态
            groupOrderSDO.getOrderLineSDOS().forEach(child -> {
                if (orderLineSDOMap.containsKey(child.getSerialNumber())) {
                    OrderLineSDO bizOrderLineSDO = orderLineSDOMap.get(child.getSerialNumber());
                    // 累计待出库数量的
                    child.setCumulativeWaitOutboundQuantity(bizOrderLineSDO.getCumulativeWaitOutboundQuantity());
                    orderLineWriteRepository.modifyOrderLine(child);
                }
            });
        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#handleGroupQuantity error", e);
        }
    }

    /**
     * 处理出入库单确认消息
     */
    private Result<Void> inOutInventoryConfirmConsumer(WarehousingOrderDTO warehousingOrderDTO) {
        Integer mainOrderType = warehousingOrderDTO.getMainOrderType();
        if (!mainOrderType.equals(WmsOrderMainTypeEnum.IN.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.RETURN_IN.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.OTHER_IN.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.SALES_OUT.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.OUT.getValue())
                && !mainOrderType.equals(WmsOrderMainTypeEnum.OTHER_OUT.getValue())) {
            return Result.success(null);
        }

        String saleOrderNo = warehousingOrderDTO.getBizOrderId();
        QueryByOrderBizIdsRequest request = new QueryByOrderBizIdsRequest();
        request.setOrderBizIds(Lists.newArrayList(saleOrderNo));
        List<OrderSDO> orderSDOS = orderQueryServiceRepository.queryByOrderBizIds(request, true);
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer orderSDOS:{}", JSON.toJSONString(orderSDOS));
        if (CollectionUtils.isEmpty(orderSDOS)) {
            return Result.success(null);
        }

        // 查询出入库单数据
        List<WarehousingOrderDTO> warehousingOrderDTOS = wmsOrderAdapter.queryWmsOrderByOtherOrder(saleOrderNo);
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer warehousingOrderDTOS={}", JSON.toJSONString(warehousingOrderDTOS));
        if (CollectionUtils.isEmpty(warehousingOrderDTOS)) {
            return Result.success(null);
        }
        //F-B-b中的B-b出入库单，过滤掉F-B的出库单,因为集成为了过账，会创建一条F-B的出库单
        OrderSDO orderSDO = orderSDOS.get(0);
        if(OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode())
                && !SalesOrderTypeEnum.GROUP_STD_ORDER.getCode().equals(orderSDO.getOrderType())){
            warehousingOrderDTOS= warehousingOrderDTOS.stream().filter(it->!it.getFeatureMap().containsKey("isBcLinkCopy")).collect(Collectors.toList());
            log.info("OrderAsyncTaskListenerServiceImpl inOutInventoryConfirmConsumer filter warehousingOrderDTOS={}", JSON.toJSONString(warehousingOrderDTOS));
        }
        List<WarehousingSubOrderDTO> allInWmsDetailList = new ArrayList<>();
        List<WarehousingSubOrderDTO> allOutWmsDetailList = new ArrayList<>();
        List<WmsOrderDetailDTO> allOutWmsDetailDTOList = new ArrayList<>();
        for (WarehousingOrderDTO warehousingOrder : warehousingOrderDTOS) {
            List<WarehousingSubOrderDTO> wmsOrderDetailList = warehousingOrder.getWmsSubOrders();
            if (CollectionUtils.isEmpty(wmsOrderDetailList)) {
                continue;
            }

            boolean in = warehousingOrder.getMainOrderType().equals(WmsOrderMainTypeEnum.IN.getValue())
                    || warehousingOrder.getMainOrderType().equals(WmsOrderMainTypeEnum.RETURN_IN.getValue())
                    || warehousingOrder.getMainOrderType().equals(WmsOrderMainTypeEnum.OTHER_IN.getValue());
            log.info("OrderAsyncTaskListenerServiceImpl inOutInventoryConfirmConsumer in:{}; mainOrderType:{}", in, warehousingOrder.getMainOrderType());
            if (in) {
                allInWmsDetailList.addAll(wmsOrderDetailList);
            } else {
                allOutWmsDetailList.addAll(wmsOrderDetailList);
                allOutWmsDetailDTOList.addAll(warehousingOrder.getWmsOrderDetailList());
            }
        }

        Map<String, OrderLineSDO> orderLineSDOMap = Nullable.stream(orderSDO.getOrderLineSDOS()).collect(Collectors.toMap(OrderLineSDO::getSerialNumber, Function.identity(), (v1, v2) -> v1));
        Map<String, Long> bizSubNoInQuantityMap = new HashMap<>();
        Map<String, Long> bizSubNoOutQuantityMap = new HashMap<>();
        Map<String, Long> bizSubNoOutAllQuantityMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(allInWmsDetailList)) {
            bizSubNoInQuantityMap = allInWmsDetailList.stream().collect(Collectors.groupingBy(WarehousingSubOrderDTO::getBizSubOrderId, Collectors.summingLong(WarehousingSubOrderDTO::getGoodsQuantity)));
        }
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer bizSubNoInQuantityMap:{}", JSON.toJSONString(bizSubNoInQuantityMap));

        if (CollectionUtils.isNotEmpty(allOutWmsDetailList)) {
            bizSubNoOutQuantityMap = allOutWmsDetailList.stream().collect(Collectors.groupingBy(WarehousingSubOrderDTO::getBizSubOrderId, Collectors.summingLong(WarehousingSubOrderDTO::getGoodsQuantity)));
        }
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer bizSubNoOutQuantityMap:{}", JSON.toJSONString(bizSubNoOutQuantityMap));

        if (CollectionUtils.isNotEmpty(allOutWmsDetailDTOList)) {
            bizSubNoOutAllQuantityMap = allOutWmsDetailDTOList.stream().collect(Collectors.groupingBy(WmsOrderDetailDTO::getBizSubOrderId, Collectors.summingLong(WmsOrderDetailDTO::getGoodsQuantity)));
        }
        log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer bizSubNoOutAllQuantityMap:{}", JSON.toJSONString(bizSubNoOutAllQuantityMap));

        try {
            for (Map.Entry<String, OrderLineSDO> lineSDOEntry : orderLineSDOMap.entrySet()) {
                String lineNo = lineSDOEntry.getKey();
                OrderLineSDO orderLineSDO = lineSDOEntry.getValue();
                JSONObject bizFeaturesJson = new JSONObject();
                if (StringUtils.isNotBlank(orderLineSDO.getBizFeatures())) {
                    bizFeaturesJson = JSONObject.parseObject(orderLineSDO.getBizFeatures());
                }
                if (SetOrderTag.EXCHANGE.equals(orderSDO.getOrderTag())) {
                    if (bizSubNoInQuantityMap.containsKey(lineNo)) {
                        BigDecimal inBoundQuantity = BigDecimal.valueOf(bizSubNoInQuantityMap.get(lineNo))
                                .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                        // 库存单位转换成销售单位
                        String cumulativeReceivedQuantity = convertUnitQuantity(inBoundQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                        orderLineSDO.setCumulativeReceivedQuantity(cumulativeReceivedQuantity);
                        completeStatus(orderLineSDO, cumulativeReceivedQuantity, SalesOrderStatusEnum.WAIT_HANDLE.getCode(), orderSDO.getFulfillmentTypeCode());
                    }
                    if (bizSubNoOutQuantityMap.containsKey(lineNo)) {
                        BigDecimal outBoundQuantity = BigDecimal.valueOf(bizSubNoOutQuantityMap.get(lineNo))
                                .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                        // 库存单位转换成销售单位
                        String deliveryAmount = convertUnitQuantity(outBoundQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                        orderLineSDO.setDeliveryAmount(StringUtils.isNotBlank(orderLineSDO.getDeliveryAmount()) ? new BigDecimal(orderLineSDO.getDeliveryAmount()).add(new BigDecimal(deliveryAmount)).toString() : deliveryAmount);
                        completeStatus(orderLineSDO, orderLineSDO.getDeliveryAmount(), SalesOrderStatusEnum.WAIT_HANDLE.getCode(), orderSDO.getFulfillmentTypeCode());
                        // 出库确认添加出库时间
                        bizFeaturesJson.put(OrderFeaturesKey.OUT_INVENTORY_CONFIRM_TIME, DateUtils.formatDate(new Date(), DateUtils.DATETIME_FORMAT));
                        orderLineSDO.setBizFeatures(JSONObject.toJSONString(bizFeaturesJson));
                    }
                } else {
                    // 出库单
                    if (bizSubNoOutQuantityMap.containsKey(lineNo)) {
                        BigDecimal outBoundQuantity = BigDecimal.valueOf(bizSubNoOutQuantityMap.get(lineNo))
                                .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                        BigDecimal outBoundAllQuantity = BigDecimal.valueOf(bizSubNoOutAllQuantityMap.get(lineNo))
                                .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                        // 库存单位转换成销售单位
                        String deliveryAmount = convertUnitQuantity(outBoundQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                        String deliveryAllAmount = convertUnitQuantity(outBoundAllQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                        orderLineSDO.setDeliveryAmount(deliveryAmount);
                        orderLineSDO.setCumulativeWaitOutboundQuantity(new BigDecimal(deliveryAllAmount).subtract(new BigDecimal(deliveryAmount)).toString());
                        completeStatus(orderLineSDO, deliveryAmount, SalesOrderStatusEnum.PARTIAL_DELIVER.getCode(), orderSDO.getFulfillmentTypeCode());

                        // 履约方式为大仓发货大仓收货、外仓发货大仓收货、虚拟移库时，才更新子状态
                        if (FulfillmentTypeEnum.CENTRAL_TO_CENTRAL.getCode().equals(orderSDO.getFulfillmentTypeCode())
                                || FulfillmentTypeEnum.EXTERNAL_TO_CENTRAL.getCode().equals(orderSDO.getFulfillmentTypeCode())
                                || FulfillmentTypeEnum.VIRTUAL.getCode().equals(orderSDO.getFulfillmentTypeCode())) {
                            // 销售/退货订单 出库后 子状态为待收货
                            orderLineSDO.setSubStatus(SalesOrderStatusEnum.WAIT_RECEIVING.getCode().toString());
                        }
                        // 出库确认添加出库时间
                        bizFeaturesJson.put(OrderFeaturesKey.OUT_INVENTORY_CONFIRM_TIME, DateUtils.formatDate(new Date(), DateUtils.DATETIME_FORMAT));
                        orderLineSDO.setBizFeatures(JSONObject.toJSONString(bizFeaturesJson));
                    }

                    // 入库单
                    if (bizSubNoInQuantityMap.containsKey(lineNo)) {
                        //如果是一盘货的F-B类型订单，不做累计已收货数量计算，因为计算B-b上的累计已出库数量已经计算过一次了
                        if (OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode())
                                && SalesOrderTypeEnum.GROUP_STD_ORDER.getCode().equals(orderSDO.getOrderType())) {
                            continue;
                        }
                        BigDecimal inBoundQuantity = BigDecimal.valueOf(bizSubNoInQuantityMap.get(lineNo))
                                .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                        // 库存单位转换成销售单位
                        String cumulativeReceivedQuantity = convertUnitQuantity(inBoundQuantity, orderLineSDO.getScItemSDO().getUnitConvert());
                        orderLineSDO.setCumulativeReceivedQuantity(cumulativeReceivedQuantity);
                        completeStatus(orderLineSDO, cumulativeReceivedQuantity, SalesOrderStatusEnum.PART_RECEIVING.getCode(), orderSDO.getFulfillmentTypeCode());

                        // 履约方式为大仓发货大仓收货、外仓发货大仓收货、虚拟移库时，才更新子状态
                        if (FulfillmentTypeEnum.CENTRAL_TO_CENTRAL.getCode().equals(orderSDO.getFulfillmentTypeCode())
                                || FulfillmentTypeEnum.EXTERNAL_TO_CENTRAL.getCode().equals(orderSDO.getFulfillmentTypeCode())
                                || FulfillmentTypeEnum.VIRTUAL.getCode().equals(orderSDO.getFulfillmentTypeCode())) {
                            if (SalesOrderStatusEnum.PART_RECEIVING.equals(SalesOrderStatusEnum.of(orderLineSDO.getStatus()))) {
                                // 子单主状态为部分交货-->子状态为部分收货
                                orderLineSDO.setSubStatus(SalesOrderStatusEnum.PARTIAL_DELIVER.getCode().toString());
                            } else if (SalesOrderStatusEnum.COMPLETED.equals(SalesOrderStatusEnum.of(orderLineSDO.getStatus()))) {
                                // 子单主状态为已完成-->子状态为已完成
                                orderLineSDO.setSubStatus(SalesOrderStatusEnum.COMPLETED.getCode().toString());
                            }
                        }
                    }
                }

                log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer orderLineSDO:{}", orderLineSDO);
                orderLineWriteRepository.modifyOrderLine(orderLineSDO);
            }
            // 推进主单状态
            allCompleteStatus(orderSDO, mainOrderType);
        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer error", e);
        }

        //库存中心发出出库确认消息后，B-b订单获取消息进行状态推进、累计已出库数量、累计待出库数量的更新后处理F-B订单状态逻辑
        if (CollectionUtils.isNotEmpty(allOutWmsDetailList)) {
            handleGroupStatus(orderSDO);
        }

        // 换货订单退货入库确认后，需要创建正向履约单
        if(SetOrderTag.EXCHANGE.equals(orderSDO.getOrderTag())) {
            if(mainOrderType.equals(WmsOrderMainTypeEnum.RETURN_IN.getValue())) {
                // 创建正向履约单
                CreateFulfillmentOrderOpenApiReq apiReq = buildCreateFulfillmentOrderOpenApiReq(warehousingOrderDTO.getWarehousingOrderId(), orderSDO);
                log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer apiReq={}", JSON.toJSONString(apiReq));
                ResponseEntity<FulfillmentOrderOpenApiResponseResult> createResult = openApiUtils.post(CREATE_ORDER_URL, JSON.toJSON(apiReq), FulfillmentOrderOpenApiResponseResult.class);
                log.info("OrderAsyncTaskListenerServiceImpl#inOutInventoryConfirmConsumer createResult={}", JSON.toJSONString(createResult));
            }
        }
        return Result.success(null);
    }

    private void allCompleteStatus(OrderSDO orderSDO, Integer mainOrderType) {
        OrderQueryRequest request = new OrderQueryRequest();
        request.setId(orderSDO.getId());
        OrderSDO querySingle = orderQueryServiceRepository.querySingle(request);
        if (SetOrderTag.EXCHANGE.equals(orderSDO.getOrderTag())) {
            if (mainOrderType.equals(WmsOrderMainTypeEnum.RETURN_IN.getValue())) {
                boolean allComplete = Nullable.stream(querySingle.getOrderLineSDOS()).filter(line -> SetOrderTag.RETURN.equals(line.getOrderLineTag())).allMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.COMPLETED.getCode()));
                boolean allPartialDeliver = Nullable.stream(querySingle.getOrderLineSDOS()).filter(line -> SetOrderTag.RETURN.equals(line.getOrderLineTag())).anyMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.WAIT_HANDLE.getCode()));
                // 所有退货行对应的入库单入库完成,发送入库完成消息
                if (allComplete) {
                    querySingle.setStatus(SalesOrderStatusEnum.WAIT_HANDLE.getCode());
                    orderWriteRepository.updateOrderStatus(querySingle);
                    sendMsgService.sendExSaleOrderInComplete(orderSDO);
                } else if (allPartialDeliver) {
                    querySingle.setStatus(SalesOrderStatusEnum.WAIT_HANDLE.getCode());
                    orderWriteRepository.updateOrderStatus(querySingle);
                }
            }
            if (mainOrderType.equals(WmsOrderMainTypeEnum.SALES_OUT.getValue())) {
                boolean allExComplete = Nullable.stream(querySingle.getOrderLineSDOS()).filter(line -> SetOrderTag.EXCHANGE.equals(line.getOrderLineTag())).allMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.COMPLETED.getCode()));
                boolean allExPartialDeliver = Nullable.stream(querySingle.getOrderLineSDOS()).filter(line -> SetOrderTag.EXCHANGE.equals(line.getOrderLineTag())).anyMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.WAIT_HANDLE.getCode()));
                // 所有换货行对应单出库单出库完成，发送完成消息
                if (allExComplete) {
                    querySingle.setStatus(SalesOrderStatusEnum.COMPLETED.getCode());
                    orderWriteRepository.updateOrderStatus(querySingle);
                    notifyExtraSystem(querySingle);
                } else if (allExPartialDeliver) {
                    querySingle.setStatus(SalesOrderStatusEnum.WAIT_HANDLE.getCode());
                    orderWriteRepository.updateOrderStatus(querySingle);
                }
            }
        } else {
            // 子单主状态都为已完成
            boolean mainCompleted = Nullable.stream(querySingle.getOrderLineSDOS())
                    .filter(line -> !line.getStatus().equals(SalesOrderStatusEnum.CANCELLED.getCode()))
                    .allMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.COMPLETED.getCode()));
            // 子单主状态存在部分交货或已完成
            boolean mainPartialDeliver = Nullable.stream(querySingle.getOrderLineSDOS())
                    .anyMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.PARTIAL_DELIVER.getCode())
                            || line.getStatus().equals(SalesOrderStatusEnum.COMPLETED.getCode()));
            // 子单主状态存在部分收货
            boolean mainPartReceiving = Nullable.stream(querySingle.getOrderLineSDOS())
                    .anyMatch(line -> line.getStatus().equals(SalesOrderStatusEnum.PART_RECEIVING.getCode()));
            log.info("OrderAsyncTaskListenerServiceImpl#allCompleteStatus mainCompleted={} mainPartialDeliver={} mainPartReceiving={}",
                    mainCompleted, mainPartialDeliver, mainPartReceiving);

            List<OrderLineSDO> filterOrderLineSDO = Nullable.stream(querySingle.getOrderLineSDOS()).filter(line -> StringUtils.isNotBlank(line.getSubStatus())).collect(Collectors.toList());
            // 子单子状态都为已完成
            boolean subCompleted = filterOrderLineSDO.stream()
                    .allMatch(line -> SalesOrderStatusEnum.COMPLETED.equals(SalesOrderStatusEnum.of(Integer.valueOf(line.getSubStatus()))));
            // 子单子状态存在待收货
            boolean subWaitReceiving = filterOrderLineSDO.stream()
                    .anyMatch(line -> SalesOrderStatusEnum.WAIT_RECEIVING.equals(SalesOrderStatusEnum.of(Integer.valueOf(line.getSubStatus())))
                            || SalesOrderStatusEnum.COMPLETED.equals(SalesOrderStatusEnum.of(Integer.valueOf(line.getSubStatus()))));
            // 子单子状态存在部分收货
            boolean subPartReceiving = filterOrderLineSDO.stream()
                    .anyMatch(line -> SalesOrderStatusEnum.PART_RECEIVING.equals(SalesOrderStatusEnum.of(Integer.valueOf(line.getSubStatus()))));
            // 子单子状态存在部分交货
            boolean subPartialDeliver = filterOrderLineSDO.stream()
                    .anyMatch(line -> SalesOrderStatusEnum.PARTIAL_DELIVER.equals(SalesOrderStatusEnum.of(Integer.valueOf(line.getSubStatus()))));
            log.info("OrderAsyncTaskListenerServiceImpl#allCompleteStatus subCompleted={} subWaitReceiving={} subPartReceiving={} subPartialDeliver={}",
                    subCompleted, subWaitReceiving, subPartReceiving, subPartialDeliver);

            if (CollectionUtils.isEmpty(filterOrderLineSDO)) {
            } else if (subCompleted) {
                // 子单子状态都为已完成，推进主单子状态为已完成
                querySingle.setSubStatus(SalesOrderStatusEnum.COMPLETED.getCode().toString());
            } else if (subPartReceiving) {
                // 子单子状态存在部分收货，推进主单子状态为部分收货
                querySingle.setSubStatus(SalesOrderStatusEnum.PART_RECEIVING.getCode().toString());
            } else if (subPartialDeliver) {
                // 子单子状态存在部分交货，推进主单子状态为部分交货
                querySingle.setSubStatus(SalesOrderStatusEnum.PARTIAL_DELIVER.getCode().toString());
            } else if (subWaitReceiving) {
                // 子单子状态存在待收货，推进主单子状态为待收货
                querySingle.setSubStatus(SalesOrderStatusEnum.WAIT_RECEIVING.getCode().toString());
            }

            if (mainCompleted) {
                // 子单主状态都为已完成时，推进主单状态为已完成
                querySingle.setStatus(SalesOrderStatusEnum.COMPLETED.getCode());
                notifyExtraSystem(querySingle);
            } else if (mainPartialDeliver) {
                // 子单主状态存在部分交货，推进主单状态为部分交货
                querySingle.setStatus(SalesOrderStatusEnum.PARTIAL_DELIVER.getCode());
            } else if (mainPartReceiving) {
                // 子单主状态存在部分收货，推进主单状态为部分收货
                querySingle.setStatus(SalesOrderStatusEnum.PART_RECEIVING.getCode());
            }

            log.info("OrderAsyncTaskListenerServiceImpl#allCompleteStatus dbOrderSDO={}", JSON.toJSONString(querySingle));
            orderWriteRepository.updateOrderStatus(querySingle);
        }
    }

    private void handleGroupStatus(OrderSDO orderSDO) {
        try {
            if (!(OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode()) && !"ZOR".equals(orderSDO.getOrderType()))) {
                return;
            }
            //查看是否是F-B的订单
            log.info("handleGroupStatus orderSDO={}",JSON.toJSONString(orderSDO));
            //F-B订单
            OrderSDO groupOrderSDO = getGroupOrder(orderSDO);
            if(Objects.isNull(groupOrderSDO)){
                return;
            }
            //B-b订单明细
            Map<String, OrderLineSDO> orderLineSDOMap = orderSDO.getOrderLineSDOS().stream().collect(Collectors.toMap(OrderLineSDO::getSerialNumber, Function.identity(), (p1, p2) -> p2));
            log.info("handleGroupStatus orderLineSDOMap={}",JSON.toJSONString(orderLineSDOMap));
            //F-B订单子单同步状态
            groupOrderSDO.getOrderLineSDOS().forEach(child -> {
                if (orderLineSDOMap.containsKey(child.getSerialNumber())) {
                    OrderLineSDO bizOrderLineSDO = orderLineSDOMap.get(child.getSerialNumber());
                    //修改F-B订单子单状态
                    child.setStatus(bizOrderLineSDO.getStatus());
                    //累计已出库数量
                    child.setDeliveryAmount(bizOrderLineSDO.getDeliveryAmount());
                    //B-b累计待出库数量=0了，这边同步一下
                    child.setCumulativeWaitOutboundQuantity(bizOrderLineSDO.getCumulativeWaitOutboundQuantity());
                    //如果B-b子单状态变更成【部分发货】则F-B子单收货状态变成【部分收货】；如果B-b子订单状态变更成【已完成】则F-B子单收货状态变成【已收货】；
                    if (SalesOrderStatusEnum.COMPLETED.getCode().equals(bizOrderLineSDO.getStatus())) {
                        child.setSubStatus(SalesOrderStatusEnum.COMPLETED.getCode().toString());
                    } else if (SalesOrderStatusEnum.PARTIAL_DELIVER.getCode().equals(bizOrderLineSDO.getStatus())) {
                        child.setSubStatus(SalesOrderStatusEnum.PART_RECEIVING.getCode().toString());
                    }
                    //累计已收货数量与B-b上的累计已出库数量保持一致
                    child.setCumulativeReceivedQuantity(bizOrderLineSDO.getDeliveryAmount());
                    orderLineWriteRepository.modifyOrderLine(child);
                }else{
                    log.error("handleGroupStatus  not exist serial number {} ",child.getSerialNumber());
                }
            });
            //状态F-B主单同步
            groupOrderSDO.setStatus(orderSDO.getStatus());
            //如果B-b订单状态变更成【部分发货】则F-B订单收货状态变成【部分收货】；如果B-b订单状态变更成【已完成】则F-B订单收货状态变成【已收货】
            if (SalesOrderStatusEnum.COMPLETED.getCode().equals(orderSDO.getStatus())) {
                groupOrderSDO.setSubStatus(SalesOrderStatusEnum.COMPLETED.getCode().toString());
            } else if (SalesOrderStatusEnum.PARTIAL_DELIVER.getCode().equals(orderSDO.getStatus())) {
                groupOrderSDO.setSubStatus(SalesOrderStatusEnum.PART_RECEIVING.getCode().toString());
            }
            orderWriteRepository.updateOrder(groupOrderSDO);
        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#handleGroupStatus error", e);
        }

    }

    private void notifyExtraSystem(OrderSDO orderSDO) {
        String message = JSON.toJSONString(orderSDO);
        Map<String, String> map = new HashMap<>();
        map.put("_CZ_KEY", BcOrderConstants.TENANT_ID());
        log.info("sendMessage SaleOrderComplete orderId = " + orderSDO.getId() + ", message = " + message + ",map = " + JSON.toJSONString(map) + " start");
        messageService.sendMessage("sale_order_message", "CR_SALEORDER_V2", "SaleOrderComplete", orderSDO.getOrderBizId(), message, map);
    }

    /**
     * 履约单消息处理（创建、修改、取消等）
     */
    @Override
    public Result<Void> fulfillmentCreatedConsumer(FulfillmentCreatedConsumerRequest fulfillmentCreatedConsumerRequest) {
        try {
            JSONObject message = JSON.parseObject(fulfillmentCreatedConsumerRequest.getMessage());
            log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer message={}", message);
            // {"data":{"orderType":"101","orderNo":"SO20240116500056","orderLine":[{"lineNo":"10","quantity":187.0}]},"eventCode":"fulfillment_order_created","eventName":"履约单创建事件","eventTime":1705655712221}

            if (Objects.isNull(message) || StringUtils.isBlank(message.toJSONString()) || StringUtils.isBlank(message.getString("eventCode"))) {
                return Result.success(null);
            }

            // 过滤事件类型，只处理【创建、修改、关闭、取消】的消息
            String eventCode = message.getString("eventCode");
            JSONObject data = message.getJSONObject("data");
            if (Objects.isNull(data)) {
                return Result.success(null);
            }
            String orderNo = data.getString("orderNo");
            if (StringUtils.isBlank(orderNo)) {
                return Result.success(null);
            }

            // 查询销售订单
            QueryByOrderBizIdsRequest request = new QueryByOrderBizIdsRequest();
            request.setOrderBizIds(Lists.newArrayList(orderNo));
            List<OrderSDO> orderSDOS = orderQueryServiceRepository.queryByOrderBizIds(request, true);
            log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer orderSDOS={}", JSON.toJSONString(orderSDOS));
            if (CollectionUtils.isEmpty(orderSDOS)) {
                return Result.success(null);
            }
            OrderSDO orderSDO = orderSDOS.get(0);
            toSap047(eventCode,data,orderSDO,message);
            //需要处理047，需要的履约的提交消息，所以把这个逻辑放在这里
            if (!FULFILLMENT_ORDER_CREATE.equals(eventCode)
                    && !FULFILLMENT_ORDER_UPDATE.equals(eventCode)
                    && !FULFILLMENT_ORDER_CANCEL.equals(eventCode)
                    && !FULFILLMENT_ORDER_CLOSE.equals(eventCode)) {
                return Result.success(null);
            }
            FulfillmentOrderSearchOrderRequest searchOrderReq = new FulfillmentOrderSearchOrderRequest();
            searchOrderReq.setBusinessType(String.valueOf(orderSDO.getBusinessType()));
            searchOrderReq.setFromSys(orderSDO.getFromSys());
            searchOrderReq.setBusinessUnitCode(orderSDO.getBusinessUnitOutCode());
            searchOrderReq.setRefOrderNo(orderSDO.getOrderBizId());
            searchOrderReq.setSize(100);
            Result<List<FulfillmentOrderDetailResDTO>> listResult = fulfillmentOrderAbilityAdapter.searchList(searchOrderReq);
            log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer listResult={}", JSON.toJSONString(listResult));
            if (Objects.isNull(listResult) || !listResult.isSuccess()) {
                return Result.success(null);
            }

            // 根据fulfillmentDirectionType区分正逆向：1正，2逆
            // 销售订单只累加正向履约单数量
            // 退货订单只累加逆向履约单数量
            Map<String, BigDecimal> quantityMap = new HashMap<>();
            for (FulfillmentOrderDetailResDTO fulfillmentOrder : listResult.getResult()) {
                log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer fulfillmentOrder={}", JSON.toJSONString(fulfillmentOrder));

                if (SetOrderTag.NORMAL.equals(orderSDO.getOrderTag()) && fulfillmentOrder.getFulfillmentDirectionType() != FULFILLMENT_ORDER_FORWARD) {
                    // 销售订单过滤逆向履约单
                    continue;
                }
                if (SetOrderTag.RETURN.equals(orderSDO.getOrderTag()) && fulfillmentOrder.getFulfillmentDirectionType() != FULFILLMENT_ORDER_REVERSE) {
                    // 退货订单过滤正向履约单
                    continue;
                }

                String refOrderLineNo = fulfillmentOrder.getRefOrderLineNo();
                if (quantityMap.containsKey(refOrderLineNo)) {
                    quantityMap.put(refOrderLineNo, quantityMap.get(refOrderLineNo).add(fulfillmentOrder.getQuantity()));
                } else {
                    quantityMap.put(refOrderLineNo, fulfillmentOrder.getQuantity());
                }
            }
            log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer quantityMap={}", JSON.toJSONString(quantityMap));

            for (OrderLineSDO orderLineSDO : orderSDO.getOrderLineSDOS()) {
                String lineNo = orderLineSDO.getSerialNumber();
                if (!quantityMap.containsKey(lineNo)) {
                    continue;
                }

                // 库存单位转换成销售单位
                String cumulativeNoticeQuantity = convertUnitQuantity(quantityMap.get(lineNo), orderLineSDO.getScItemSDO().getUnitConvert());
                if (StringUtils.isNotBlank(orderLineSDO.getCumulativeNoticeQuantity()) && orderLineSDO.getCumulativeNoticeQuantity().equals(cumulativeNoticeQuantity)) {
                    // 值相等时不更新db，减少性能开销
                    continue;
                }

                orderLineSDO.setCumulativeNoticeQuantity(cumulativeNoticeQuantity);
                finishFulfillmentStatus(orderLineSDO);
                log.info("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer orderLineSDO={}", JSON.toJSONString(orderLineSDO));
                UpdateCumulativeNoticeQuantityAndFeaturesRequest noticeQuantityAndFeaturesRequest = new UpdateCumulativeNoticeQuantityAndFeaturesRequest();
                noticeQuantityAndFeaturesRequest.setOrderLineId(Long.valueOf(orderLineSDO.getId()));
                noticeQuantityAndFeaturesRequest.setCumulativeNoticeQuantity(cumulativeNoticeQuantity);
                noticeQuantityAndFeaturesRequest.setFeatures(JSON.toJSONString(orderLineSDO.getFeatures()));
                UpdateCumulativeNoticeQuantityAndFeaturesResponse response = orderLineWriteRepository.updateCumulativeNoticeQuantityAndFeatures(noticeQuantityAndFeaturesRequest);
                log.info("OrderAsyncTaskListenerServiceImpl fulfillmentCreatedConsumer response ={}",JSON.toJSONString(response));
            }
            handleGroupNoticeQuantity(orderSDO);

        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#fulfillmentCreatedConsumer error", e);
        }
        return Result.success(null);
    }
    private void toSap047(String eventCode,JSONObject data,OrderSDO orderSDO,JSONObject message){
        //发送履约单提交消息、关闭消息
        if((FULFILLMENT_ORDER_SUBMIT.equals(eventCode)
                || FULFILLMENT_ORDER_CLOSE.equals(eventCode)|| FULFILLMENT_ORDER_CANCEL.equals(eventCode)) && isF2B(orderSDO)){
            data.put("businessType",orderSDO.getBusinessType());
            message.put("data",data);
            try{
                sendMsgService.sendConfirmQuantityMsg(JSON.toJSONString(message));
            }catch (Exception e ){
                log.error("OrderAsyncTaskListenerServiceImpl fulfillmentCreatedConsumer sendConfirmQuantityMsg error",e);
            }
        }
    }
    private boolean isF2B(OrderSDO order){
        String[] orderType = {"ZFOC","ZOR","ZOR8"};
        List<String> orderTypeList = Arrays.asList(orderType);
        return OrderCategoryEnum.GROUP.getCode().equals(order.getOrderCategoryCode()) && orderTypeList.contains(order.getOrderType());
    }
    private void finishFulfillmentStatus(OrderLineSDO orderLineSDO) {
        log.info("OrderAsyncTaskListenerServiceImpl#finishFulfillmentStatus orderLineSDO:{}", JSON.toJSONString(orderLineSDO));
        String cumulativeNoticeQuantity = orderLineSDO.getCumulativeNoticeQuantity();
        String quantity = orderLineSDO.getQuantity();
        Map<String, String> features = orderLineSDO.getFeatures();
        if (StringUtils.isBlank(cumulativeNoticeQuantity) && StringUtils.isBlank(quantity)) {
            // 如果累计通知数为空，默认待履约状态
            features.put(OrderFeaturesKey.FULFILLMENT_STATUS, FulfillmentStatusEnum.BEFORE_FULFILLMENT.getCode());
        } else {
            int cumulativeNoticeQuantityInt = Integer.parseInt(cumulativeNoticeQuantity);
            int quantityInt = Integer.parseInt(quantity);
            if (cumulativeNoticeQuantityInt == 0) {
                // 累计通知数 == 0， fulfillmentStatus为待履约
                features.put(OrderFeaturesKey.FULFILLMENT_STATUS, FulfillmentStatusEnum.BEFORE_FULFILLMENT.getCode());
            } else if (cumulativeNoticeQuantityInt < quantityInt) {
                // 累计通知数 < 销售数量， fulfillmentStatus为部分履约
                features.put(OrderFeaturesKey.FULFILLMENT_STATUS, FulfillmentStatusEnum.PARTIAL_FULFILLMENT.getCode());
            } else {
                // 累计通知数 >= 销售数量， fulfillmentStatus为已完成
                features.put(OrderFeaturesKey.FULFILLMENT_STATUS, FulfillmentStatusEnum.COMPLETED.getCode());
            }
        }
        orderLineSDO.setFeatures(features);
    }

    private void handleGroupNoticeQuantity(OrderSDO orderSDO) {
        try {
            if (!OrderCategoryEnum.STOCK.getCode().equals(orderSDO.getOrderCategoryCode())) {
                return;
            }
            //F-B订单
            OrderSDO groupOrderSDO = getGroupOrder(orderSDO);
            //B-b订单明细
            Map<String, OrderLineSDO> orderLineSDOMap = orderSDO.getOrderLineSDOS().stream().collect(Collectors.toMap(OrderLineSDO::getSerialNumber, Function.identity(), (p1, p2) -> p2));
            //F-B订单子单同步状态
            groupOrderSDO.getOrderLineSDOS().forEach(child -> {
                if (orderLineSDOMap.containsKey(child.getSerialNumber())) {
                    OrderLineSDO bizOrderLineSDO = orderLineSDOMap.get(child.getSerialNumber());
                    // 累计通知数量
                    child.setCumulativeNoticeQuantity(bizOrderLineSDO.getCumulativeNoticeQuantity());
                    orderLineWriteRepository.modifyOrderLine(child);
                }
            });
        } catch (Exception e) {
            log.error("OrderAsyncTaskListenerServiceImpl#handleGroupQuantity error", e);
        }

    }

    /**
     * 订单事件消息处理（创建、更新、取消、关闭、SAP创建等）
     */
    @Override
    public Result<Void> salesOrderEventConsumer(SalesOrderEventConsumerRequest salesOrderEventConsumerRequest) {
        log.info("salesOrderEventConsumerRequest参数:{}",JSON.toJSONString(salesOrderEventConsumerRequest));
        if (StringUtils.isBlank(salesOrderEventConsumerRequest.getMessage())) {
            return Result.success(null);
        }
        JSONObject messageObj = JSONObject.parseObject(salesOrderEventConsumerRequest.getMessage());
        String eventCode = messageObj.getString("eventCode");
        if (InnerMessageEventEnum.SALES_ORDER_CREATED_SAP.getValue().equals(eventCode)) {
            JSONArray orderList = messageObj.getJSONArray("data");
            JSONObject orderJson = orderList.getJSONObject(0);
            OrderSDO orderSDO = orderJson.toJavaObject(OrderSDO.class);
            // 换货订单需要创建逆向履约单
            if (SetOrderTag.EXCHANGE.equals(orderSDO.getOrderTag()) && "true".equals(orderSDO.getAutoFulfillment())) {
                CreateReverseFulfillmentOrderOpenApiReq apiReq = buildCreateReverseFulfillmentOrderOpenApiReq(orderSDO);
                log.info("OrderAsyncTaskListenerServiceImpl#salesOrderEventConsumer apiReq={}", JSON.toJSONString(apiReq));
                ResponseEntity<FulfillmentOrderOpenApiResponseResult> createResult = openApiUtils.post(CREATE_REVERSE_ORDER_URL, JSON.toJSON(apiReq), FulfillmentOrderOpenApiResponseResult.class);
                log.info("OrderAsyncTaskListenerServiceImpl#salesOrderEventConsumer createResult={}", JSON.toJSONString(createResult));
            }
        }
        return Result.success(null);
    }

    private CreateFulfillmentOrderOpenApiReq buildCreateFulfillmentOrderOpenApiReq(String requestNo, OrderSDO order) {
        CreateFulfillmentOrderOpenApiReq apiReq = new CreateFulfillmentOrderOpenApiReq();
        BeanUtils.copyProperties(order, apiReq);
        //请求编码
        apiReq.setRequestNo(requestNo);
        //履约方式
        apiReq.setFulfillmentType(FulfillmentTypeEnum.CENTRAL_TO_CENTRAL.getCode());
        //履约优先级
        apiReq.setPriority(order.getFulfillmentPriority());
        //发货仓编码（逻辑仓）编码
        apiReq.setLogicShippingWarehouseCode(order.getWareHouseOutCode());
        //销售组织
        apiReq.setSalesOrganizationCode(order.getOrganizationOutCode());
        //送达方
        apiReq.setShipToPartyCode(order.getReceiveAddressCode());
        //售达方
        apiReq.setSoldToPartyCode(order.getCustomerCode());
        //收货仓编码
        apiReq.setLogicReceivingWarehouseCode(order.getReceiveWareHouseOutCode());
        //创建人
        apiReq.setCreator(order.getCreatorCode());
        //期望交货日期
        apiReq.setExpectedDeliveryDate(TimeUtil.formatYYYY_MM_dd(order.getCustomerExpectDate()));
        //配送方式编码
        apiReq.setShippingMethodCode(order.getTransportModeCode());

        // 按履约中心要求，将创建人名称放到扩展字段里
        JSONObject bizFeatures = new JSONObject();
        bizFeatures.put("createName", order.getCreatorName2());
        apiReq.setBizFeatures(bizFeatures.toJSONString());

        List<CreateFulfillmentOrderDetailOpenApiDTO> detailList = Lists.newArrayList();
        //明细行，需要处理，找到修改中增加的数量
        List<OrderLineSDO> orderLineSDOS = order.getOrderLineSDOS();
        List<OrderLineSDO> exchangeOrderLines = orderLineSDOS.stream().filter(orderLine -> SetOrderTag.EXCHANGE.equals(orderLine.getOrderLineTag())).collect(Collectors.toList());
        exchangeOrderLines.forEach(orderLineSDO -> {
            CreateFulfillmentOrderDetailOpenApiDTO createFulfillmentOrderDetail = new CreateFulfillmentOrderDetailOpenApiDTO();
            createFulfillmentOrderDetail.setRefOrderNo(order.getOrderBizId());
            createFulfillmentOrderDetail.setRefOrderLineNo(orderLineSDO.getSerialNumber());
            createFulfillmentOrderDetail.setSourceOrderLineNo(orderLineSDO.getSourceLineNum());
            createFulfillmentOrderDetail.setRefOrderCreateTime(DateUtils.toDateStr(order.getGmtCreate(), "yyyy-MM-dd HH:mm:ss"));
            createFulfillmentOrderDetail.setMaterialCode(orderLineSDO.getScItemSDO().getScItemOutCode());
            createFulfillmentOrderDetail.setSaleQuantity(orderLineSDO.getScItemSDO().getQuantity() == null ? "0" : String.valueOf(orderLineSDO.getScItemSDO().getQuantity()));
            createFulfillmentOrderDetail.setRemark(orderLineSDO.getRemark());
            createFulfillmentOrderDetail.setProductionDate(DateUtils.toDateStr(orderLineSDO.getScItemSDO().getProductationTime(), "yyyy-MM-dd"));
            createFulfillmentOrderDetail.setSalesUnitCode(orderLineSDO.getScItemSDO().getSaleUnit());
            createFulfillmentOrderDetail.setShippingUnitCode(orderLineSDO.getScItemSDO().getInventoryUnitCode());
            BigDecimal quantity = new BigDecimal(orderLineSDO.getScItemSDO().getQuantity() == null ? 0 : orderLineSDO.getScItemSDO().getQuantity());
            BigDecimal quantityOfInventory = quantity.divide(new BigDecimal(orderLineSDO.getScItemSDO().getUnitConvert()), 3, RoundingMode.HALF_UP);
            createFulfillmentOrderDetail.setQuantity(String.valueOf(quantityOfInventory));
            createFulfillmentOrderDetail.setBizFeatures(orderLineSDO.getBizFeatures());
            detailList.add(createFulfillmentOrderDetail);
        });
        apiReq.setDetailList(detailList);
        apiReq.setAutoSubmit("1");
        //业态编码
        apiReq.setBusinessType(String.valueOf(order.getBusinessType()));
        //业务单元编码
        apiReq.setBusinessUnitCode(order.getBusinessUnitOutCode());
        //来源单号
        apiReq.setSourceOrderNo(order.getOrderBizId());
        //业务单据类型
        apiReq.setRefOrderType(OrderTypeEnum.SALE_OUTBOUND.getValue());
        return apiReq;
    }

    private CreateReverseFulfillmentOrderOpenApiReq buildCreateReverseFulfillmentOrderOpenApiReq(OrderSDO order) {
        CreateReverseFulfillmentOrderOpenApiReq apiReq = new CreateReverseFulfillmentOrderOpenApiReq();
        BeanUtils.copyProperties(order, apiReq);
        //请求编码
        apiReq.setRequestNo(UUID.randomUUID().toString());
        //履约方式
        apiReq.setFulfillmentType(FulfillmentTypeEnum.CENTRAL_TO_CENTRAL.getCode());
        //履约优先级
        apiReq.setPriority(order.getFulfillmentPriority());
        //发货仓编码（逻辑仓）编码
        apiReq.setLogicShippingWarehouseCode(order.getWareHouseOutCode());
        //销售组织
        apiReq.setSalesOrganizationCode(order.getOrganizationOutCode());
        //送达方
        apiReq.setShipToPartyCode(order.getReceiveAddressCode());
        //售达方
        apiReq.setSoldToPartyCode(order.getCustomerCode());
        //收货仓编码
        apiReq.setLogicReceivingWarehouseCode(order.getReceiveWareHouseOutCode());
        //创建人
        apiReq.setCreator(order.getCreatorName());
        //期望交货日期
        apiReq.setExpectedDeliveryDate(TimeUtil.formatYYYY_MM_dd(order.getCustomerExpectDate()));
        //配送方式编码
        apiReq.setShippingMethodCode(order.getTransportModeCode());

        // 按履约中心要求，将创建人名称放到扩展字段里
        JSONObject bizFeatures = new JSONObject();
        bizFeatures.put("createName", order.getCreatorName2());
        apiReq.setBizFeatures(bizFeatures.toJSONString());

        List<CreateFulfillmentOrderDetailOpenApiDTO> detailList = Lists.newArrayList();
        //明细行，需要处理，找到修改中增加的数量
        List<OrderLineSDO> orderLineSDOS = order.getOrderLineSDOS();
        List<OrderLineSDO> returnOrderLines = orderLineSDOS.stream().filter(orderLine -> SetOrderTag.RETURN.equals(orderLine.getOrderLineTag())).collect(Collectors.toList());
        returnOrderLines.forEach(orderLineSDO -> {
            CreateFulfillmentOrderDetailOpenApiDTO createFulfillmentOrderDetail = new CreateFulfillmentOrderDetailOpenApiDTO();
            createFulfillmentOrderDetail.setRefOrderNo(order.getOrderBizId());
            createFulfillmentOrderDetail.setRefOrderLineNo(orderLineSDO.getSerialNumber());
            createFulfillmentOrderDetail.setSourceOrderLineNo(orderLineSDO.getSerialNumber());
            createFulfillmentOrderDetail.setRefOrderCreateTime(DateUtils.toDateStr(order.getGmtCreate(), "yyyy-MM-dd HH:mm:ss"));
            createFulfillmentOrderDetail.setMaterialCode(orderLineSDO.getScItemSDO().getScItemOutCode());
            createFulfillmentOrderDetail.setSaleQuantity(orderLineSDO.getScItemSDO().getQuantity() == null ? "0" : String.valueOf(orderLineSDO.getScItemSDO().getQuantity()));
            createFulfillmentOrderDetail.setRemark(orderLineSDO.getRemark());
            createFulfillmentOrderDetail.setProductionDate(DateUtils.toDateStr(orderLineSDO.getScItemSDO().getProductationTime(), "yyyy-MM-dd"));
            createFulfillmentOrderDetail.setSalesUnitCode(orderLineSDO.getScItemSDO().getSaleUnit());
            createFulfillmentOrderDetail.setShippingUnitCode(orderLineSDO.getScItemSDO().getInventoryUnitCode());
            BigDecimal quantity = new BigDecimal(orderLineSDO.getScItemSDO().getQuantity() == null ? 0 : orderLineSDO.getScItemSDO().getQuantity());
            BigDecimal quantityOfInventory = quantity.divide(new BigDecimal(orderLineSDO.getScItemSDO().getUnitConvert()), 3, RoundingMode.HALF_UP);
            createFulfillmentOrderDetail.setQuantity(String.valueOf(quantityOfInventory));
            createFulfillmentOrderDetail.setBizFeatures(orderLineSDO.getBizFeatures());
            detailList.add(createFulfillmentOrderDetail);
        });
        apiReq.setDetailList(detailList);
        apiReq.setAutoSubmit("1");
        //业态编码
        apiReq.setBusinessType(String.valueOf(order.getBusinessType()));
        //业务单元编码
        apiReq.setBusinessUnitCode(order.getBusinessUnitOutCode());
        //来源单号
        apiReq.setSourceOrderNo(order.getOrderBizId());
        //业务单据类型
        apiReq.setRefOrderType(OrderTypeEnum.SALE_RETURN_INBOUND.getValue());
        return apiReq;
    }

    private void completeStatus(OrderLineSDO orderLineSDO, String amount, Integer nextStatus, String fulfillmentTypeCode) {
        BigDecimal deliveryAmount = new BigDecimal(StringUtils.isBlank(amount) ? "0" : amount);
        BigDecimal quantity = new BigDecimal(orderLineSDO.getQuantity());
        if (deliveryAmount.compareTo(quantity) >= 0) {
            orderLineSDO.setStatus(SalesOrderStatusEnum.COMPLETED.getCode());
            if (!FulfillmentTypeEnum.VIRTUAL.equals(FulfillmentTypeEnum.of(fulfillmentTypeCode))) {
                orderLineSDO.setCumulativeWaitOutboundQuantity("0");
            }
        } else {
            orderLineSDO.setStatus(nextStatus);
        }
    }

    @Override
    public Result<Void> salesOrderSapEventConsumer(SalesOrderSapEventConsumerRequest salesOrderSapEventConsumerRequest) {
        log.info("OrderAsyncTaskListenerServiceImpl salesOrderSapEventConsumer salesOrderSapEventConsumerRequest={}",JSON.toJSONString(salesOrderSapEventConsumerRequest));
        try{
            SalesOrderSapEventMessage message = JSON.parseObject(salesOrderSapEventConsumerRequest.getMessage(),SalesOrderSapEventMessage.class);
            log.info("OrderAsyncTaskListenerServiceImpl salesOrderSapEventConsumer message={}",JSON.toJSONString(message));
            return handleSapUpdateAmount(message.getSdo(),message.getOrderAndDetailResponse());
        }catch (Exception e){
            return Result.fail("OC-05-001-01-15-001","消息解析异常");
        }
    }

    @Override
    public Result<Void> salesOrderCloseConsumer(SalesOrderCloseConsumerRequest salesOrderCloseConsumerRequest) {
        log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer salesOrderCloseConsumerRequest:{}", JSON.toJSONString(salesOrderCloseConsumerRequest));
        CommonAsyncMessageResponse commonAsyncMessageResponse = JSON.parseObject(salesOrderCloseConsumerRequest.getMessage(), CommonAsyncMessageResponse.class);
        log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer commonAsyncMessageResponse:{}", JSON.toJSONString(commonAsyncMessageResponse));
        if (!(InnerMessageEventEnum.SALES_ORDER_REFUSED.getValue().equals(commonAsyncMessageResponse.getEventCode()) || InnerMessageEventEnum.SALES_ORDER_CANCELED.getValue().equals(commonAsyncMessageResponse.getEventCode()))) {
            return Result.success(null);
        }
        List<OrderSDO> orderSDOList = JSON.parseArray(JSON.toJSONString(commonAsyncMessageResponse.getData()), OrderSDO.class);
        Set<String> forecastOrderIdSet = new HashSet<>();
        for (OrderSDO orderSDO : orderSDOList) {
            forecastOrderIdSet.addAll(orderSDO.getOrderLineSDOS().stream().map(v -> String.format("%s_%s", orderSDO.getPreOrderNo(), v.getSourceLineNum())).collect(Collectors.toSet()));
        }
        log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer orderSDOList:{}", JSON.toJSONString(orderSDOList));
        if (CollectionUtils.isEmpty(orderSDOList)) {
            return Result.success(null);
        }
        QueryByOrderBizIdsRequest request = new QueryByOrderBizIdsRequest();
        request.setPreOrderNoList(orderSDOList.stream().map(OrderSDO::getPreOrderNo).collect(Collectors.toList()));
        request.setLimit(999);
        List<OrderSDO> dbOrderSDOS = orderQueryServiceRepository.queryByOrderBizIds(request, true);
        log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer dbOrderSDOS:{}", JSON.toJSONString(dbOrderSDOS));
        if (CollectionUtils.isEmpty(dbOrderSDOS)) {
            return Result.success(null);
        }
        Map<String, List<OrderSDO>> orderSDOMap = dbOrderSDOS.stream().filter(order -> StringUtils.isNotBlank(order.getPreOrderNo())).collect(Collectors.groupingBy(OrderSDO::getPreOrderNo));
        List<String> preOrderNoList = Lists.newArrayList(orderSDOMap.keySet());
        if (CollectionUtils.isEmpty(preOrderNoList)) {
            return Result.success(null);
        }
        List<ForecastOrderSDO> forecastOrderSDOList = forecastOrderQueryRepository.queryByOrderBizNo(preOrderNoList);
        log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer forecastOrderSDOList:{}", JSON.toJSONString(forecastOrderSDOList));
        if (CollectionUtils.isEmpty(forecastOrderSDOList)) {
            return Result.success(null);
        }
        Map<String, ForecastOrderSDO> forecastOrderMap = forecastOrderSDOList.stream().collect(Collectors.toMap(ForecastOrderSDO::getOrderBizId, Function.identity(), (k1, k2) -> k2));
        List<ForecastOrderSDO> updateForecastOrderList = new ArrayList<>();
        for (Map.Entry<String, List<OrderSDO>> entry : orderSDOMap.entrySet()) {
            ForecastOrderSDO forecastOrderSDO = forecastOrderMap.get(entry.getKey());
            if (Objects.isNull(forecastOrderSDO)) {
                continue;
            }
            List<ForecastOrderLineSDO> forecastOrderLineSDOList = forecastOrderSDO.getForecastOrderLineSDOList();
            if (CollectionUtils.isEmpty(forecastOrderLineSDOList)) {
                continue;
            }
            List<OrderLineSDO> orderLineSDOS = entry.getValue().stream().flatMap(orderSDO -> orderSDO.getOrderLineSDOS().stream()).collect(Collectors.toList());
            callBackLine(forecastOrderLineSDOList, orderLineSDOS, forecastOrderIdSet, forecastOrderSDO.getOrderBizId());
            log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer forecastOrderLineSDOList:{}", forecastOrderLineSDOList);

            if (CollectionUtils.isNotEmpty(forecastOrderLineSDOList)) {
                boolean isWaitingForReply = forecastOrderLineSDOList.stream().allMatch(v -> ForecastStatusEnum.WAITING_FOR_REPLY.equals(ForecastStatusEnum.of(v.getStatus())));

                boolean isCompleted = forecastOrderLineSDOList.stream().allMatch(v -> ForecastStatusEnum.COMPLETED.equals(ForecastStatusEnum.of(v.getStatus())));

                // boolean iPartialReply = forecastOrderLineSDOList.stream().anyMatch(v -> ForecastStatusEnum.PARTIAL_REPLY.equals(ForecastStatusEnum.of(v.getStatus())));

                if (isWaitingForReply) {
                    forecastOrderSDO.setStatus(ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue());
                } else if (isCompleted) {
                    forecastOrderSDO.setStatus(ForecastStatusEnum.COMPLETED.getNumValue());
                } else {
                    forecastOrderSDO.setStatus(ForecastStatusEnum.PARTIAL_REPLY.getNumValue());
                }
            }
            updateForecastOrderList.add(forecastOrderSDO);
        }
        for (ForecastOrderSDO forecastOrderSDO : updateForecastOrderList) {
            ForecastOrder forecastOrder = new ForecastOrder();
            forecastOrder.setId(Long.valueOf(forecastOrderSDO.getId()));
            forecastOrder.setStatus(forecastOrderSDO.getStatus());
            log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer forecastOrder:{}", JSON.toJSONString(forecastOrder));
            forecastOrderService.updateForecastOrder(forecastOrder);
            for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrderSDO.getForecastOrderLineSDOList()) {
                ForecastOrderLine forecastOrderLine = new ForecastOrderLine();
                forecastOrderLine.setId(Long.valueOf(forecastOrderLineSDO.getId()));
                forecastOrderLine.setStatus(forecastOrderLineSDO.getStatus());
                forecastOrderLine.setGmt_modified(forecastOrderLineSDO.getGmtModified());
                forecastOrderLine.setActualTotalReplyAmount(forecastOrderLineSDO.getActualTotalReplyAmount());
                forecastOrderLine.setBizFeatures(forecastOrderLineSDO.getBizFeatures());
                log.info("OrderAsyncTaskListenerServiceImpl#salesOrderCloseConsumer forecastOrderLine:{}", JSON.toJSONString(forecastOrderLine));
                forecastOrderLineService.updateForecastOrderLine(forecastOrderLine);
            }
        }
        return Result.success(null);
    }

    private void callBackLine(List<ForecastOrderLineSDO> forecastOrderLineSDOList, List<OrderLineSDO> orderLineSDOList, Set<String> forecastOrderIdSet, String forecastOrderBizId) {
        log.info("OrderAsyncTaskListenerServiceImpl#callBackLine before forecastOrderLineSDOList:{}; orderLineSDOList:{}", JSON.toJSONString(forecastOrderLineSDOList), JSON.toJSONString(orderLineSDOList));
        Map<String, List<OrderLineSDO>> orderLineMap = orderLineSDOList.stream().collect(Collectors.groupingBy(OrderLineSDO::getSourceLineNum));
        for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrderLineSDOList) {
            List<OrderLineSDO> orderLineSDOS = orderLineMap.get(forecastOrderLineSDO.getSerialNumber());
            if (CollectionUtils.isEmpty(orderLineSDOList) || CollectionUtils.isEmpty(orderLineSDOS)) {
                continue;
            }
            forecastOrderLineSDO.setGmtModified(new Date());
            Integer actualTotalReplyAmount = 0;
            for (OrderLineSDO orderLineSDO : orderLineSDOS) {
                Integer salesQuantity = 0;
                if (SalesOrderStatusEnum.COMPLETED.equals(SalesOrderStatusEnum.of(orderLineSDO.getStatus()))) {
                    if (0 == orderLineSDO.getClosed()) {
                        salesQuantity = StringUtils.isBlank(orderLineSDO.getQuantity()) ? 0 : Integer.valueOf(orderLineSDO.getQuantity());
                    } else {
                        salesQuantity = StringUtils.isBlank(orderLineSDO.getDeliveryAmount()) ? 0 : Integer.valueOf(orderLineSDO.getDeliveryAmount());
                    }
                } else if (SalesOrderStatusEnum.BEFORE_DELIVERY.equals(SalesOrderStatusEnum.of(orderLineSDO.getStatus())) || SalesOrderStatusEnum.PARTIAL_DELIVER.equals(SalesOrderStatusEnum.of(orderLineSDO.getStatus()))) {
                    salesQuantity = StringUtils.isBlank(orderLineSDO.getQuantity()) ? 0 : Integer.valueOf(orderLineSDO.getQuantity());
                }
                actualTotalReplyAmount += salesQuantity;
            }
            forecastOrderLineSDO.setActualTotalReplyAmount(actualTotalReplyAmount);
            if (forecastOrderIdSet.contains(String.format("%s_%s", forecastOrderBizId, forecastOrderLineSDO.getSerialNumber()))) {
                String bizFeatures = forecastOrderLineSDO.getBizFeatures();
                if (StringUtils.isNotBlank(bizFeatures)) {
                    JSONObject jsonObject = JSONObject.parseObject(bizFeatures);
                    jsonObject.remove("reasonCode");
                    jsonObject.remove("reasonName");
                    jsonObject.remove("analysisTime");
                    forecastOrderLineSDO.setBizFeatures(jsonObject.toJSONString());
                }
            }
            Integer forecastQuantity = Integer.valueOf(forecastOrderLineSDO.getQuantity());
            if (actualTotalReplyAmount == 0) {
                forecastOrderLineSDO.setStatus(ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue());
            } else if (forecastQuantity > actualTotalReplyAmount) {
                forecastOrderLineSDO.setStatus(ForecastStatusEnum.PARTIAL_REPLY.getNumValue());
            } else if (forecastQuantity <= actualTotalReplyAmount) {
                forecastOrderLineSDO.setStatus(ForecastStatusEnum.COMPLETED.getNumValue());
            }
        }
        log.info("OrderAsyncTaskListenerServiceImpl#callBackLine after forecastOrderLineSDOList:{}; orderLineSDOList:{}", JSON.toJSONString(forecastOrderLineSDOList), JSON.toJSONString(orderLineSDOList));
    }

    private Result<Void> handleSapUpdateAmount(MnSapIf013SDO sdo, OrderAndDetailResponse orderAndDetail) {
        String redisKey = String.format("%s-%s", "sapUpdateAmountSync", sdo.getHeaderKey());
        try (SaleRedisLock lock = new SaleRedisLock(CACHE_CODE, redisKey, TIMEOUT_MSECS, EXPIRE_MSECS, SLEEP_MILLIS)) {
            if (!lock.lock()) {
                log.error("OrderAsyncTaskListenerServiceImpl handleSapUpdateAmount obtain lock fail lockKey={}", redisKey);
                throw new FunctionException("分布式锁获取失败");
            }
            if (Objects.isNull(orderAndDetail)){
                return Result.success(null);
            }
            List<OrderLine> orderLineList = orderAndDetail.getOrderLineList();
            Order order = orderAndDetail.getOrder();
            //查询履约单明细
            List<BcFulfillmentOrderDetailSearchResponse> searchResponse = getBcFulfillmentOrderDetail(order);
            if (CollectionUtils.isEmpty(searchResponse)){
                //查询不到履约单，需要MQ异步处理，重试机制
                throw new FunctionException("查询履约单不存在");
            }

            searchResponse = searchResponse.stream().filter(it->"1".equals(it.getFulfillmentDirectionType())).collect(Collectors.toList());

            //是否修改了数量，并且履约单的数量和sap的数量不一致
            if(isModifyAmount(sdo,orderLineList) && isDiff(sdo,searchResponse)){
                try {
                    doModifyAmount(order,orderLineList,sdo,searchResponse);
                }catch (Exception e ){
                    log.error("handleSapUpdateAmount doModifyAmount error",e);
                }
            }
            if(sdo.getItems().size()>orderLineList.size()){
                //如果sap增加了明细行，直接调用新增接口
                MnSapIf013SDO mnSapIf013SDO = new MnSapIf013SDO();
                BeanUtils.copyProperties(sdo,mnSapIf013SDO);
                List<String> existOrderLineSerialNumbers = orderLineList.stream().map(OrderLine::getSerialNumber).collect(Collectors.toList());
                List<MnSapIf013Detail> newDetail = sdo.getItems().stream().filter(it -> !existOrderLineSerialNumbers.contains(abandonZero(it.getItem_key()))).collect(Collectors.toList());
                mnSapIf013SDO.setItems(newDetail);
                log.info("OrderAsyncTaskListenerServiceImpl doModifyAmount mnSapIf013SDO={}",JSON.toJSONString(mnSapIf013SDO));
                try{
                    handleNewOrderLine(order,mnSapIf013SDO,orderLineList);
                }catch (Exception e){
                    log.error("handleSapUpdateAmount doNew error",e);
                }
            }
            //是否关闭了明细行
            if(isCloseLine(sdo)){
                try {
                    doCloseLine(order,sdo,searchResponse);
                }catch (Exception e){
                    log.error("handleSapUpdateAmount doCloseLine error",e);
                }
            }

        }catch (Exception e){
            log.error(" handleSapUpdateAmount error ",e);
        }
        return Result.success(null);
    }

    private boolean isDiff(MnSapIf013SDO sdo, List<BcFulfillmentOrderDetailSearchResponse> searchResponse) {
        List<MnSapIf013Detail> items = sdo.getItems();
        log.info("OrderAsyncTaskListenerServiceImpl isDiff items={}",JSON.toJSONString(items));
        Map<String, List<BcFulfillmentOrderDetailSearchResponse>> lineNoMap = searchResponse.stream().collect(Collectors.groupingBy(BcFulfillmentOrderDetailSearchResponse::getLineNumber));
        Map<String,Integer> lineNoQuantity = new HashMap<>();
        lineNoMap.forEach((key,value)->{
            AtomicInteger sum = new AtomicInteger();
            value.stream().forEach(it->sum.addAndGet(Double.valueOf(it.getQuantity()).intValue()));
            lineNoQuantity.put(key,sum.intValue());
        });
        log.info("OrderAsyncTaskListenerServiceImpl isDiff lineNoQuantity={}",JSON.toJSONString(lineNoQuantity));
        for (int i = 0; i < items.size(); i++) {
            MnSapIf013Detail item = items.get(i);
            String itemKey = abandonZero(item.getItem_key());
            if(lineNoQuantity.containsKey(itemKey)){
                Integer quantity = lineNoQuantity.get(itemKey);
                //是否和履约单数量一致，sap返回的是携带了三位小数，需要裁切掉
                if(!Objects.equals(quantity,Integer.valueOf(item.getQuantity().split("\\.")[0]))){
                    return true;
                }
            }
        }
        return false;
    }

    private String abandonZero(String itemKey){
        return itemKey.replaceAll("^0+", "");
    }

    private void doCloseLine(Order order, MnSapIf013SDO sdo, List<BcFulfillmentOrderDetailSearchResponse> searchResponse) {
        //关闭的订单明细行
        Map<String, MnSapIf013Detail> closeLineNoMap = sdo.getItems().stream().filter(it-> org.apache.commons.lang3.StringUtils.isNotBlank(it.getCloseReason())).collect(Collectors.toMap(MnSapIf013Detail::getItemKey,Function.identity(),(p1, p2)->p2));

        Map<String, List<BcFulfillmentOrderDetailSearchResponse>> detailListMap = searchResponse.stream().collect(Collectors.groupingBy(BcFulfillmentOrderDetailSearchResponse::getFulfillmentOrderNo));
        List<FinishReq.FulfillmentOrderInfo> list = Lists.newArrayList();
        detailListMap.forEach((key,value)->{
            //每一个主单都有明细，需要找出哪些需要关闭的，出库是基于明细行号的，如果出库单中某个明细行号已经全部出库了，就不需要关闭了
            for (int i = 0; i < value.size(); i++) {
                BcFulfillmentOrderDetailSearchResponse v = value.get(i);
                if(!closeLineNoMap.containsKey(v.getRefOrderLineNo())){
                    continue;
                }
                MnSapIf013Detail mnSapIf013Detail = closeLineNoMap.get(v.getLineNumber());
                FinishReq.FulfillmentOrderInfo orderInfo = new FinishReq.FulfillmentOrderInfo();
                orderInfo.setFulfillmentOrderNo(key);
                orderInfo.setFulfillmentSubOrderNo(Integer.valueOf(v.getLineNumber()));
                orderInfo.setReason(mnSapIf013Detail.getCloseCode());
                list.add(orderInfo);
            }
        });
        doCloseFulfillmentOrder(list,order,sdo);
    }

    /**
     * 先根据销售订单查询关联的出库单，累计算出明细行对应的累计出库创建数量，计算销售订单数量与累计出库创建数量的差值，如果等于0查询对应的履约单，将该销售订单明细行对应的履约单上履约数量改成累计出库创建数量；
     * 如果等于0查询对应的履约单，将该销售订单明细行对应的履约单上履约数量改成累计出库创建数量；
     * 如果大于0查询对应的履约单，将该销售订单明细行对应的履约单上履约数量改成累计出库创建数量，同时按照差值生成新的履约单，操作成功后按照SAP修改的数据修改销售订单数量。
     */
    private void doModifyAmount(Order order, List<OrderLine> orderLineList, MnSapIf013SDO sdo, List<BcFulfillmentOrderDetailSearchResponse> searchResponse) {
        List<MnSapIf013Detail> items = sdo.getItems();
        //查询出库单
        List<WarehousingOrderDTO> warehousingOrders = wmsOrderAdapter.queryWmsOrderByOtherOrder(order.getOrderBizId());

        //基于明细行号累计出库创建数量
        Map<String,Long> lineNoMap=new HashMap<>();

        if (CollectionUtils.isEmpty(warehousingOrders)) {
            orderLineList.forEach(item -> lineNoMap.put(item.getSerialNumber(), 0L));
        } else {
            //出库单
            warehousingOrders.forEach(item->{
                //出入库明细
                List<WmsOrderDetailDTO> wmsSubOrders = item.getWmsOrderDetailList().stream().filter(it->Byte.valueOf((byte)1).equals(it.getStatus()) || Byte.valueOf((byte)2).equals(it.getStatus())).collect(Collectors.toList());
                //遍历明细行，基于明细行号做累加处理
                wmsSubOrders.forEach(detail->{
                    //如果存在了就累加，不存在就新增
                    if(lineNoMap.containsKey(detail.getBizSubOrderId())){
                        Long exist = lineNoMap.get(detail.getBizSubOrderId());
                        lineNoMap.put(detail.getBizSubOrderId(),detail.getGoodsQuantity()+exist);
                    }else {
                        lineNoMap.put(detail.getBizSubOrderId(),detail.getGoodsQuantity());
                    }
                });
            });
        }
        log.info("doModifyAmount lineNoMap={}",JSON.toJSONString(lineNoMap));

        //订单明细的销售数量
        Map<String,Long> orderLineMap = new HashMap<>();
        items.forEach(item-> orderLineMap.put(abandonZero(item.getItem_key()),Long.valueOf(item.getQuantity().split("\\.")[0])));
        log.info("doModifyAmount orderLineMap={}",JSON.toJSONString(orderLineMap));
        //计算出哪些明细行号，没有出库完，还存在部分待出库的，这些待出库的就是需要重新生成履约单
        Map<String, BigDecimal> remainMap = new HashMap<>();
        orderLineMap.forEach((key,value)->{
            if (lineNoMap.containsKey(key)){
                //已经出库的数量
                BigDecimal quantity = BigDecimal.valueOf(lineNoMap.get(key))
                        .divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                //剩余未出库的数量
                BigDecimal remain = BigDecimal.valueOf(value).subtract(quantity);
                if (remain.compareTo(BigDecimal.ZERO) > 0) {
                    remainMap.put(key,remain);
                }
            } else {
                remainMap.put(key,BigDecimal.valueOf(value));
            }
        });
        log.info("doModifyAmount remainMap={}",JSON.toJSONString(remainMap));

        //返回值是主子明细打平的状态,，需要按照主单分组
        Map<String, List<BcFulfillmentOrderDetailSearchResponse>> detailListMap = searchResponse.stream().collect(Collectors.groupingBy(BcFulfillmentOrderDetailSearchResponse::getFulfillmentOrderNo));
        List<FinishReq.FulfillmentOrderInfo> list = Lists.newArrayList();
        detailListMap.forEach((key,value)->{
            //每一个主单都有明细，需要找出哪些需要关闭的，出库是基于明细行号的，如果出库单中某个明细行号已经全部出库了，就不需要关闭了
            for (int i = 0; i < value.size(); i++) {
                BcFulfillmentOrderDetailSearchResponse v = value.get(i);
                if("8".equals(v.getDetailStatus())){
                    continue;
                }
                //履约单行号
                String lineNumber = v.getLineNumber();
                //如果这个履约单行号还存在待出货的，就需要关闭当前履约明细行
                if (remainMap.containsKey(lineNumber)){
                    FinishReq.FulfillmentOrderInfo orderInfo = new FinishReq.FulfillmentOrderInfo();
                    orderInfo.setFulfillmentOrderNo(key);
                    orderInfo.setFulfillmentSubOrderNo(Integer.valueOf(v.getLineNumber()));
//                    orderInfo.setReason("U1");
                    list.add(orderInfo);
                }
            }
        });

        ResponseEntity<BcBatchCloseFulfillmentOrderOpenApiResponseResult> resultResponseEntity = doCloseFulfillmentOrder(list, order, sdo);
        if (Objects.isNull(resultResponseEntity) || Objects.isNull(resultResponseEntity.getBody())){
            return;
        }

        BcBatchCloseFulfillmentOrderOpenApiResponseResult body = resultResponseEntity.getBody();
        if(CollectionUtils.isEmpty(body.getResult())){
            return;
        }
        //有任意一个失败就当作失败
        Optional<BatchCloseFulfillmentOrderOpenApiResponse> any = body.getResult().stream().filter(it -> !it.getSuccess()).findAny();
        //关闭失败就不新增了
        if (!body.isSuccess() || any.isPresent()){
            handleFail(order,body);
            return;
        }

        if(!remainMap.isEmpty()){
            //计算修改数量的明细行
            MnSapIf013SDO mnSapIf013SDO = new MnSapIf013SDO();
            BeanUtils.copyProperties(sdo,mnSapIf013SDO);
            List<String> existOrderLineSerialNumbers = orderLineList.stream().map(OrderLine::getSerialNumber).collect(Collectors.toList());
            List<MnSapIf013Detail> oldDetail = sdo.getItems().stream().filter(it -> existOrderLineSerialNumbers.contains(abandonZero(it.getItem_key()))).collect(Collectors.toList());
            mnSapIf013SDO.setItems(oldDetail);
            log.info("OrderAsyncTaskListenerServiceImpl doModifyAmount oldMnSapIf013SDO={}",JSON.toJSONString(mnSapIf013SDO));
            doCreateFulfillmentOrder(order,mnSapIf013SDO,orderLineList,remainMap);
        }
    }

    private void doCreateFulfillmentOrder(Order order, MnSapIf013SDO mnSapIf013SDO, List<OrderLine> orderLineList, Map<String, BigDecimal> remainMap){
        CreateFulfillmentOrderOpenApiReq apiReq = buildCreateFulfillmentOrderOpenApiReq(order,mnSapIf013SDO,orderLineList,remainMap);
        log.info("OrderAsyncTaskListenerServiceImpl doCreateFulfillmentOrder apiReq={}",JSON.toJSONString(apiReq));
        //如果大于0需要创建新的履约单
        ResponseEntity<FulfillmentOrderOpenApiResponseResult> createResult = openApiUtils.post(CREATE_ORDER_URL, JSON.toJSON(apiReq), FulfillmentOrderOpenApiResponseResult.class);
        log.info("OrderAsyncTaskListenerServiceImpl doCreateFulfillmentOrder createResult={}",JSON.toJSONString(createResult));
    }

    private void handleNewOrderLine(Order order, MnSapIf013SDO sdo, List<OrderLine> existOrderLineList) {
        //找到新增的数据
        QuerySalesOrderLineByIdsRequest querySalesOrderLineByIdsRequest = new QuerySalesOrderLineByIdsRequest();
        //查询中台的订单明细信息
        querySalesOrderLineByIdsRequest.setMainOrderId(String.valueOf(order.getId()));
        Result<List<OrderLine>> listResult = orderLineService.querySalesOrderLineByIds(querySalesOrderLineByIdsRequest);
        log.info("OrderAsyncTaskListenerServiceImpl handleNewOrderLine listResult={}",JSON.toJSONString(listResult));
        if(Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())){
            return;
        }
        //已经存在的明细行
        List<String> existSerialNumber = existOrderLineList.stream().map(OrderLine::getSerialNumber).collect(Collectors.toList());
        //现在数据的所有明细
        List<OrderLine> orderLineList = listResult.getResult();
        //新增的明细行
        List<OrderLine> newOrderLine = orderLineList.stream().filter(it -> !existSerialNumber.contains(it.getSerialNumber())).collect(Collectors.toList());
        //key = sap的明细行号 value = 物料编码
        Map<String, String> itemKeyItemCodeMap = sdo.getItems().stream().filter(it -> !existSerialNumber.contains(it.getItemKey())).collect(Collectors.toMap(MnSapIf013Detail::getItemKey, MnSapIf013Detail::getItemCode,(p1,p2)->p1));
        List<String> scItemOutIds = sdo.getItems().stream().filter(it -> !existSerialNumber.contains(it.getItemKey())).map(MnSapIf013Detail::getItemCode).collect(Collectors.toList());
        log.info("OrderAsyncTaskListenerServiceImpl handleNewOrderLine itemKeyItemCodeMap={}",JSON.toJSONString(itemKeyItemCodeMap));
        //为了共用逻辑，设置剩余数量就是明细行的销售数量
        Map<String,BigDecimal> remainMap = new HashMap<>();
        // 物料
        ItemSearchAbilityRequest listRequest = new ItemSearchAbilityRequest();
        listRequest.setProductCodes(scItemOutIds);
        listRequest.setStatusList(Collections.singletonList(1));
        List<ItemSearchAbilityDTO> scItemInfoList = itemQueryAdapter.queryItem(listRequest);
        Map<String, ItemSearchAbilityDTO> scItemInfoMap = Optional.ofNullable(scItemInfoList)
                .orElse(Lists.newArrayList())
                .stream().collect(Collectors.toMap(ItemSearchAbilityDTO::getOuterId, p -> p, (v1, v2) -> v1));
        log.info("OrderAsyncTaskListenerServiceImpl handleNewOrderLine scItemInfoMap={}",JSON.toJSONString(scItemInfoMap));
        //箱柜关系
        List<SpecConvertCoefficientDTO> specConvertCoefficientDTOS =
                itemSpecQueryAdapter.queryConvertCoefficientByMaterialCodeList(scItemOutIds);
        Map<String, SpecConvertCoefficientDTO> productConvertRelationMap = specConvertCoefficientDTOS.stream().collect(
                Collectors.toMap(SpecConvertCoefficientDTO::getMaterialCode, p -> p, (v1, v2) -> v1));
        log.info("OrderAsyncTaskListenerServiceImpl handleNewOrderLine productConvertRelationMap={}",JSON.toJSONString(productConvertRelationMap));
        //销售单位、库存单位
        ItemUnitAbilityRequest itemUnitAbilityRequest = new ItemUnitAbilityRequest();
        itemUnitAbilityRequest.setLimit(999);
        List<ItemUnitAbilityDTO> listResponse = itemQueryAdapter.queryScItemUnitMap(itemUnitAbilityRequest);
        Map<String, ItemUnitAbilityDTO> scItemUnitMap = listResponse.stream().collect(Collectors.toMap(ItemUnitAbilityDTO::getUnitCode, p -> p, (v1, v2) -> v1));
        log.info("OrderAsyncTaskListenerServiceImpl handleNewOrderLine scItemUnitMap={}",JSON.toJSONString(scItemUnitMap));
        List<OrderLine> newOrderLineTemp = new ArrayList<>();
        for (int i = 0; i < newOrderLine.size(); i++) {
            OrderLine it = newOrderLine.get(i);
            remainMap.put(it.getSerialNumber(), BigDecimal.valueOf(it.getQuantity()));
            //设置物料编码
            it.setScItemOutCode(itemKeyItemCodeMap.get(it.getSerialNumber()));
            //设置来源行号
            it.setSourceLineNum(it.getSerialNumber());
            //主单业务单号
            it.setMainOrderBizId(order.getOrderBizId());
            //单位转换关系
            if(!productConvertRelationMap.containsKey(it.getScItemOutCode())){
                log.error("OrderAsyncTaskListenerServiceImpl handleNewOrderLine itemOutCode {} does not product convert relation",it.getScItemOutCode());
               break;
            }
            SpecConvertCoefficientDTO productConvert = productConvertRelationMap.get(it.getScItemOutCode());
            List<SpecConvertCoefficientDetailDTO> convertRelations = productConvert.getConvertCoefficientList();
            // 销售单位
            if(!scItemUnitMap.containsKey(it.getSaleUnit())){
                log.error("OrderAsyncTaskListenerServiceImpl handleNewOrderLine saleUnit {}  does not item unit",it.getSaleUnit());
                break;
            }
            ItemUnitAbilityDTO scItemUnit = scItemUnitMap.get(it.getSaleUnit());
            for (SpecConvertCoefficientDetailDTO convertRelation : convertRelations) {
                if (StringUtils.equals(convertRelation.getUnitCode(), scItemUnit.getUnitCode())) {
                    Integer convertCoefficient = convertRelation.getConvertCoefficient();
                    ////单位转换关系
                    it.setUnitConvert(String.valueOf(convertCoefficient));
                    break;
                }
            }
            //库存单位编码
            if(!scItemInfoMap.containsKey(it.getScItemOutCode())){
                log.error("OrderAsyncTaskListenerServiceImpl handleNewOrderLine itemOutCode {}  does not item info",it.getSaleUnit());
                break;
            }
            ItemSearchAbilityDTO scItem = scItemInfoMap.get(it.getScItemOutCode());
            it.setInventoryUnitCode(scItem.getUnitCode());
            newOrderLineTemp.add(it);
        }
        if (CollectionUtils.isNotEmpty(newOrderLineTemp)){
            doCreateFulfillmentOrder(order,sdo,newOrderLine,remainMap);
        }else{
            log.error("OrderAsyncTaskListenerServiceImpl handleNewOrderLine lack parameter error");
        }

    }

    private void handleFail(Order order, BcBatchCloseFulfillmentOrderOpenApiResponseResult body) {
        //如果失败了，需要记录信息到订单的bizFeatures
        String message = body.getMessage();
        String bizFeatures = order.getBizFeatures();
        Map<String,String> map = new HashMap<>();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(bizFeatures)){
            map = JSON.parseObject(bizFeatures,Map.class);
        }
        map.put("msg",message);
        order.setBizFeatures(JSON.toJSONString(map));
        UpdateOrderResponse updateOrderResponse = orderService.updateOrder(order);
        log.info("OrderAsyncTaskListenerServiceImpl handleFail response={}",JSON.toJSONString(updateOrderResponse));
    }

    private ResponseEntity<BcBatchCloseFulfillmentOrderOpenApiResponseResult> doCloseFulfillmentOrder(List<FinishReq.FulfillmentOrderInfo> list, Order order, MnSapIf013SDO sdo){
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        //构建批量关闭的请求参数
        FinishReq finishReq = new FinishReq();
        finishReq.setFulfillmentOrderInfoList(list);
        finishReq.setFromSys(order.getFromSys());
        finishReq.setBusinessType(String.valueOf(order.getBusinessType()));
        finishReq.setBusinessUnitCode(order.getBisUnitOutCode());
        finishReq.setUpdater(DEFAULT_USER);
        //调用关闭接口
        ResponseEntity<BcBatchCloseFulfillmentOrderOpenApiResponseResult> outFinishResult = openApiUtils.post(CLOSE_ORDER_URL,JSON.toJSON(finishReq), BcBatchCloseFulfillmentOrderOpenApiResponseResult.class);
        log.info("OrderAsyncTaskListenerServiceImpl#doModifyAmount#outFinishResult={}",JSON.toJSONString(outFinishResult));
        return outFinishResult;
    }

    private List<BcFulfillmentOrderDetailSearchResponse> getBcFulfillmentOrderDetail(Order order) {
        int pageSize =100;
        SearchOrderOpenApiReq searchOrderOpenApiReq = new SearchOrderOpenApiReq();
        searchOrderOpenApiReq.setBusinessType(String.valueOf(order.getBusinessType()));
        searchOrderOpenApiReq.setSourceOrderNo(order.getOrderBizId());
        searchOrderOpenApiReq.setPage(1);
        searchOrderOpenApiReq.setSize(pageSize);
        ResponseEntity<BcFulfillmentOrderDetailSearchResponseResult> outResult = openApiUtils.post(SEARCH_ORDER_URL, JSON.toJSON(searchOrderOpenApiReq), BcFulfillmentOrderDetailSearchResponseResult.class);
        log.info("OrderAsyncTaskListenerServiceImpl#doModifyAmount#outResult={}",JSON.toJSONString(outResult));
        if(Objects.isNull(outResult) || Objects.isNull(outResult.getBody())){
            return new ArrayList<>();
        }
        List<BcFulfillmentOrderDetailSearchResponse> result = outResult.getBody().getResult();
        Integer total = outResult.getBody().getTotal();
        int size = outResult.getBody().getResult().size();
        if (total>size){
            int remain = total-size;
            int page  =  remain %pageSize ==0? (remain/pageSize):(remain/pageSize+1);
            for (int i = 1; i <= page; i++) {
                searchOrderOpenApiReq.setPage(i+1);
                ResponseEntity<BcFulfillmentOrderDetailSearchResponseResult> pageOutResult = openApiUtils.post(SEARCH_ORDER_URL, JSON.toJSON(searchOrderOpenApiReq), BcFulfillmentOrderDetailSearchResponseResult.class);
                log.info("OrderAsyncTaskListenerServiceImpl#doModifyAmount#pageOutResult={}",JSON.toJSONString(pageOutResult));
                if(Objects.isNull(pageOutResult) || Objects.isNull(pageOutResult.getBody())){
                    break;
                }
                result.addAll(pageOutResult.getBody().getResult());
            }
        }
        return result;
    }

    private CreateFulfillmentOrderOpenApiReq buildCreateFulfillmentOrderOpenApiReq(Order order, MnSapIf013SDO sdo,List<OrderLine> orderLineList, Map<String, BigDecimal> remainMap) {
        CreateFulfillmentOrderOpenApiReq apiReq = new CreateFulfillmentOrderOpenApiReq();
        BeanUtils.copyProperties(order,apiReq);
        //请求编码
        apiReq.setRequestNo(UUID.randomUUID().toString());
        //履约方式
        apiReq.setFulfillmentType("100");
        //履约优先级
        apiReq.setPriority(order.getFulfillmentPriority());
        //发货仓编码（逻辑仓）编码
        apiReq.setLogicShippingWarehouseCode(order.getWareHouseOutCode());
        //销售组织
        apiReq.setSalesOrganizationCode(order.getOrganizationOutCode());
        //送达方
        apiReq.setShipToPartyCode(order.getReceiveAddressCode());
        //售达方
        apiReq.setSoldToPartyCode(order.getCustomerCode());
        //收货仓编码
        apiReq.setLogicReceivingWarehouseCode(order.getReceiveWareHouseOutCode());
        //创建人
        apiReq.setCreator(order.getCreatorCode());
        //期望交货日期
        apiReq.setExpectedDeliveryDate(TimeUtil.formatYYYY_MM_dd(order.getCustomerExpectDate()));
        //配送方式编码
        apiReq.setShippingMethodCode(order.getTransportModeCode());

        // 按履约中心要求，将创建人名称放到扩展字段里
        JSONObject bizFeatures = new JSONObject();
        bizFeatures.put("createName", order.getCreatorName2());
        apiReq.setBizFeatures(bizFeatures.toJSONString());

        List<CreateFulfillmentOrderDetailOpenApiDTO> detailList = Lists.newArrayList();
        //明细行，需要处理，找到修改中增加的数量
        Map<String, OrderLine> orderLineMap = orderLineList.stream().collect(Collectors.toMap(OrderLine::getOuterOrderLineId, Function.identity(), (p1, p2) -> p2));
        log.info("buildCreateFulfillmentOrderOpenApiReq#,remainMap={},orderLineMap={}",JSON.toJSONString(remainMap),JSON.toJSONString(orderLineMap));
        sdo.getItems().forEach(item->{
            CreateFulfillmentOrderDetailOpenApiDTO detailOpenApiDTO = new CreateFulfillmentOrderDetailOpenApiDTO();
            String itemKey = abandonZero(item.getItem_key());
            if(remainMap.containsKey(itemKey) && orderLineMap.containsKey(itemKey)){
                OrderLine orderLine = orderLineMap.get(itemKey);
                detailOpenApiDTO.setSourceOrderLineNo(orderLine.getSourceLineNum());
                detailOpenApiDTO.setRefOrderNo(orderLine.getMainOrderBizId());
                detailOpenApiDTO.setRefOrderLineNo(orderLine.getSerialNumber());
                detailOpenApiDTO.setRefOrderCreateTime(TimeUtil.formatYYYY_MM_dd_time(orderLine.getGmtCreate()));
                detailOpenApiDTO.setMaterialCode(orderLine.getScItemOutCode());
                detailOpenApiDTO.setProductionDate(TimeUtil.formatYYYY_MM_dd(orderLine.getProductationTime()));
                detailOpenApiDTO.setSalesUnitCode(orderLine.getSaleUnit());
                String unitConvert = orderLine.getUnitConvert().split("\\.")[0];
                //待出库数量
                BigDecimal remain = remainMap.get(itemKey);
                detailOpenApiDTO.setSaleQuantity(String.valueOf(remain.intValue()));
                //库存单位数量
                BigDecimal divide = remain.divide(BigDecimal.valueOf(Long.parseLong(unitConvert)), 3, RoundingMode.HALF_UP);
                detailOpenApiDTO.setQuantity(divide.toEngineeringString());
                detailOpenApiDTO.setShippingUnitCode(orderLine.getInventoryUnitCode());
                detailOpenApiDTO.setRemark(orderLine.getRemark());
                detailOpenApiDTO.setBizFeatures(orderLine.getBizFeatures());
                detailList.add(detailOpenApiDTO);
            }
        });
        apiReq.setDetailList(detailList);

        apiReq.setAutoSubmit("1");
        //业态编码
        apiReq.setBusinessType(String.valueOf(order.getBusinessType()));
        //业务单元编码
        apiReq.setBusinessUnitCode(order.getBisUnitOutCode());
        //来源单号
        apiReq.setSourceOrderNo(order.getOrderBizId());
        //业务单据类型
        apiReq.setRefOrderType("101");
        return apiReq;
    }

    private boolean isCloseLine(MnSapIf013SDO sdo) {
        return sdo.getItems().stream().anyMatch(it -> org.apache.commons.lang3.StringUtils.isNotBlank(it.getCloseCode()));
    }

    private boolean isModifyAmount(MnSapIf013SDO sdo, List<OrderLine> result) {
        List<MnSapIf013Detail> items = sdo.getItems();
        //明细行map,key = outerOrderLineId value = OrderLine
        Map<String, OrderLine> orderLineMap = result.stream().collect(Collectors.toMap(OrderLine::getOuterOrderLineId, Function.identity(), (p1, p2) -> p2));
        for (int i = 0; i < items.size(); i++) {
            MnSapIf013Detail item = items.get(i);
            String itemKey = abandonZero(item.getItem_key());
            if(orderLineMap.containsKey(itemKey)){
                OrderLine orderLine = orderLineMap.get(itemKey);
                //是否修改了数量，sap返回的是携带了三位小数，需要裁切掉
                if(!Objects.equals(orderLine.getQuantity(),Integer.valueOf(item.getQuantity().split("\\.")[0]))){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 库存单位转换成销售单位
     */
    private String convertUnitQuantity(BigDecimal quantity, String unitConvert) {
        // 库存数量*转换系数=销售数量，保留整数，小数位四舍五入
        return quantity.multiply(new BigDecimal(unitConvert))
                .setScale(0, RoundingMode.HALF_UP)
                .toString();
    }
}
